commit 82af0bc97507eb3a7e89b4d7f66ba968419fea30
parent 21d9a6dbfc8a1a8be0cc7997dc84e50a57dc5c9a
Author: Christian Grothoff <christian@grothoff.org>
Date: Thu, 4 Jun 2026 23:00:56 +0200
stasis: replace database plugin with directly-linked libanastasisdb
and modernize libgnunetpq API usage
- Removes plugin_anastasis_postgres.c, anastasis_db_plugin.c (the dlopen
loader) and anastasis_database_plugin.h.
- Splits the monolithic plugin into one implementation file per database
operation (src/stasis/anastasis-db_*.c) plus shared connection,
transaction and event helpers in anastasis-db_pg.{c,h}.
- Adds one header per operation under
include/anastasis/anastasis-database/, so each compilation unit only
includes the database headers it actually uses. anastasis_database_lib.h
becomes the umbrella header and declares ANASTASIS_DB_init/_fini.
- Updates all callers (backend httpd, authorization plugins, IBAN helper,
anastasis-dbinit, test) to call ANASTASIS_DB_* directly instead of
db->func(db->cls, ...). Drop the now-unused db handle from the
authorization plugin context and loader.
- Update meson build accordingly.
- new GNUNET_PQ_init() with proper DB connection loss handling
- PREPARE macro use to prepare on-demand
Not yet pretty ('pq' global without proper prefix, some tests still
failing), but major progress.
Diffstat:
96 files changed, 5853 insertions(+), 4393 deletions(-)
diff --git a/src/authorization/anastasis-helper-authorization-iban.c b/src/authorization/anastasis-helper-authorization-iban.c
@@ -76,11 +76,6 @@ static struct GNUNET_CURL_RescheduleContext *rc;
static const struct GNUNET_CONFIGURATION_Handle *cfg;
/**
- * Our DB plugin.
- */
-static struct ANASTASIS_DatabasePlugin *db_plugin;
-
-/**
* How long should we sleep when idle before trying to find more work?
* Useful in case bank does not support long polling.
*/
@@ -173,10 +168,10 @@ notify (const char *sender_account_uri,
&ev.debit_iban_hash);
GNUNET_free (iban);
as = TALER_amount2s (amount);
- db_plugin->event_notify (db_plugin->cls,
- &ev.header,
- as,
- strlen (as));
+ ANASTASIS_DB_event_notify (
+ &ev.header,
+ as,
+ strlen (as));
}
@@ -209,8 +204,7 @@ shutdown_task (void *cls)
GNUNET_SCHEDULER_cancel (task);
task = NULL;
}
- ANASTASIS_DB_plugin_unload (db_plugin);
- db_plugin = NULL;
+ ANASTASIS_DB_fini ();
ANASTASIS_EUFIN_auth_free (&auth);
cfg = NULL;
}
@@ -286,13 +280,13 @@ history_cb (void *cls,
char *dcanon = payto_get_iban (details->debit_account_uri);
char *ccanon = payto_get_iban (details->credit_account_uri);
- qs = db_plugin->record_auth_iban_payment (db_plugin->cls,
- serial_id,
- details->wire_subject,
- &details->amount,
- dcanon,
- ccanon,
- details->execution_date);
+ qs = ANASTASIS_DB_record_auth_iban_payment (
+ serial_id,
+ details->wire_subject,
+ &details->amount,
+ dcanon,
+ ccanon,
+ details->execution_date);
GNUNET_free (ccanon);
GNUNET_free (dcanon);
}
@@ -380,10 +374,10 @@ run (void *cls,
(void) cls;
(void) args;
(void) cfgfile;
+
cfg = c;
- if (NULL ==
- (db_plugin = ANASTASIS_DB_plugin_load (cfg,
- false)))
+ if (GNUNET_OK !=
+ ANASTASIS_DB_init (cfg))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Database not set up. Did you run anastasis-dbinit?\n");
@@ -400,8 +394,7 @@ run (void *cls,
"authorization-iban",
"CREDIT_IBAN");
global_ret = EXIT_NOTCONFIGURED;
- ANASTASIS_DB_plugin_unload (db_plugin);
- db_plugin = NULL;
+ ANASTASIS_DB_fini ();
return;
}
@@ -412,23 +405,21 @@ run (void *cls,
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to load bank access configuration data\n");
- ANASTASIS_DB_plugin_unload (db_plugin);
- db_plugin = NULL;
+ ANASTASIS_DB_fini ();
global_ret = EXIT_NOTCONFIGURED;
return;
}
{
enum GNUNET_DB_QueryStatus qs;
- qs = db_plugin->get_last_auth_iban_payment_row (db_plugin->cls,
- authorization_iban,
- &latest_row_off);
+ qs = ANASTASIS_DB_get_last_auth_iban_payment_row (
+ authorization_iban,
+ &latest_row_off);
if (qs < 0)
{
GNUNET_break (0);
ANASTASIS_EUFIN_auth_free (&auth);
- ANASTASIS_DB_plugin_unload (db_plugin);
- db_plugin = NULL;
+ ANASTASIS_DB_fini ();
return;
}
}
diff --git a/src/authorization/anastasis_authorization_plugin.c b/src/authorization/anastasis_authorization_plugin.c
@@ -77,7 +77,6 @@ struct AuthPlugin
struct ANASTASIS_AuthorizationPlugin *
ANASTASIS_authorization_plugin_load (
const char *method,
- struct ANASTASIS_DatabasePlugin *db,
const struct GNUNET_CONFIGURATION_Handle *AH_cfg)
{
struct ANASTASIS_AuthorizationPlugin *authorization;
@@ -103,7 +102,6 @@ ANASTASIS_authorization_plugin_load (
return NULL;
}
ap = GNUNET_new (struct AuthPlugin);
- ap->ac.db = db;
ap->ac.cfg = AH_cfg;
if (GNUNET_OK !=
TALER_config_get_amount (AH_cfg,
diff --git a/src/authorization/anastasis_authorization_plugin_email.c b/src/authorization/anastasis_authorization_plugin_email.c
@@ -262,9 +262,9 @@ email_start (void *cls,
plugin is already happy (no additional
requirements), so mark this challenge as
already satisfied from the start. */
- qs = ctx->ac->db->mark_challenge_code_satisfied (ctx->ac->db->cls,
- truth_uuid,
- code);
+ qs = ANASTASIS_DB_mark_challenge_code_satisfied (
+ truth_uuid,
+ code);
if (qs <= 0)
{
GNUNET_break (0);
diff --git a/src/authorization/anastasis_authorization_plugin_file.c b/src/authorization/anastasis_authorization_plugin_file.c
@@ -130,17 +130,17 @@ file_start (void *cls,
const void *data,
size_t data_length)
{
- const struct ANASTASIS_AuthorizationContext *ac = cls;
struct ANASTASIS_AUTHORIZATION_State *as;
enum GNUNET_DB_QueryStatus qs;
+ (void) cls;
/* If the user can show this challenge code, this
plugin is already happy (no additional
requirements), so mark this challenge as
already satisfied from the start. */
- qs = ac->db->mark_challenge_code_satisfied (ac->db->cls,
- truth_uuid,
- code);
+ qs = ANASTASIS_DB_mark_challenge_code_satisfied (
+ truth_uuid,
+ code);
if (qs <= 0)
{
GNUNET_break (0);
diff --git a/src/authorization/anastasis_authorization_plugin_iban.c b/src/authorization/anastasis_authorization_plugin_iban.c
@@ -365,8 +365,6 @@ static enum
}
test_wire_transfers (struct ANASTASIS_AUTHORIZATION_State *as)
{
- struct IBAN_Context *ctx = as->ctx;
- struct ANASTASIS_DatabasePlugin *db = ctx->ac->db;
enum GNUNET_DB_QueryStatus qs;
struct GNUNET_TIME_Absolute now;
struct GNUNET_TIME_Timestamp limit;
@@ -377,8 +375,7 @@ test_wire_transfers (struct ANASTASIS_AUTHORIZATION_State *as)
limit = GNUNET_TIME_absolute_to_timestamp (
GNUNET_TIME_absolute_subtract (now,
CODE_VALIDITY_PERIOD));
- qs = db->test_auth_iban_payment (
- db->cls,
+ qs = ANASTASIS_DB_test_auth_iban_payment (
as->iban_number,
limit,
&check_payment_ok,
@@ -399,8 +396,7 @@ test_wire_transfers (struct ANASTASIS_AUTHORIZATION_State *as)
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
break;
}
- qs = db->mark_challenge_code_satisfied (
- db->cls,
+ qs = ANASTASIS_DB_mark_challenge_code_satisfied (
&as->truth_uuid,
as->code);
GNUNET_break (qs > 0);
@@ -522,8 +518,6 @@ iban_solve (struct ANASTASIS_AUTHORIZATION_State *as,
const struct GNUNET_HashCode *challenge_response,
struct MHD_Connection *connection)
{
- struct IBAN_Context *ctx = as->ctx;
- struct ANASTASIS_DatabasePlugin *db = ctx->ac->db;
enum MHD_Result mres;
enum GNUNET_DB_QueryStatus qs;
struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
@@ -540,20 +534,20 @@ iban_solve (struct ANASTASIS_AUTHORIZATION_State *as,
GNUNET_CRYPTO_hash (as->iban_number,
strlen (as->iban_number),
&espec.debit_iban_hash);
- as->eh = db->event_listen (db->cls,
- &espec.header,
- GNUNET_TIME_absolute_get_remaining (
- timeout),
- &bank_event_cb,
- as);
+ as->eh = ANASTASIS_DB_event_listen (
+ &espec.header,
+ GNUNET_TIME_absolute_get_remaining (
+ timeout),
+ &bank_event_cb,
+ as);
}
after = GNUNET_TIME_absolute_to_timestamp (
GNUNET_TIME_absolute_subtract (now,
CODE_VALIDITY_PERIOD));
- qs = db->test_challenge_code_satisfied (db->cls,
- &as->truth_uuid,
- as->code,
- after);
+ qs = ANASTASIS_DB_test_challenge_code_satisfied (
+ &as->truth_uuid,
+ as->code,
+ after);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
@@ -617,11 +611,9 @@ iban_solve (struct ANASTASIS_AUTHORIZATION_State *as,
static void
iban_cleanup (struct ANASTASIS_AUTHORIZATION_State *as)
{
- struct IBAN_Context *ctx = as->ctx;
-
if (NULL != as->eh)
{
- ctx->ac->db->event_listen_cancel (as->eh);
+ ANASTASIS_DB_event_listen_cancel (as->eh);
as->eh = NULL;
}
GNUNET_free (as->iban_number);
diff --git a/src/authorization/anastasis_authorization_plugin_post.c b/src/authorization/anastasis_authorization_plugin_post.c
@@ -292,9 +292,9 @@ post_start (void *cls,
plugin is already happy (no additional
requirements), so mark this challenge as
already satisfied from the start. */
- qs = ctx->ac->db->mark_challenge_code_satisfied (ctx->ac->db->cls,
- truth_uuid,
- code);
+ qs = ANASTASIS_DB_mark_challenge_code_satisfied (
+ truth_uuid,
+ code);
if (qs <= 0)
{
GNUNET_break (0);
diff --git a/src/authorization/anastasis_authorization_plugin_sms.c b/src/authorization/anastasis_authorization_plugin_sms.c
@@ -261,9 +261,9 @@ sms_start (void *cls,
plugin is already happy (no additional
requirements), so mark this challenge as
already satisfied from the start. */
- qs = ctx->ac->db->mark_challenge_code_satisfied (ctx->ac->db->cls,
- truth_uuid,
- code);
+ qs = ANASTASIS_DB_mark_challenge_code_satisfied (
+ truth_uuid,
+ code);
if (qs <= 0)
{
GNUNET_break (0);
diff --git a/src/backend/anastasis-httpd.c b/src/backend/anastasis-httpd.c
@@ -113,11 +113,6 @@ struct GNUNET_CONTAINER_Heap *AH_to_heap;
static int global_result;
/**
- * Connection handle to the our database
- */
-struct ANASTASIS_DatabasePlugin *db;
-
-/**
* Reschedule context for #AH_ctx.
*/
static struct GNUNET_CURL_RescheduleContext *rc;
@@ -482,11 +477,7 @@ do_shutdown (void *cls)
GNUNET_CURL_gnunet_rc_destroy (rc);
rc = NULL;
}
- if (NULL != db)
- {
- ANASTASIS_DB_plugin_unload (db);
- db = NULL;
- }
+ ANASTASIS_DB_fini ();
if (NULL != AH_to_heap)
{
GNUNET_CONTAINER_heap_destroy (AH_to_heap);
@@ -819,15 +810,8 @@ run (void *cls,
GNUNET_free (auth_header);
}
- if (NULL ==
- (db = ANASTASIS_DB_plugin_load (config,
- false)))
- {
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
if (GNUNET_OK !=
- db->connect (db->cls))
+ ANASTASIS_DB_init (config))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Database not setup. Did you run anastasis-dbinit?\n");
diff --git a/src/backend/anastasis-httpd.h b/src/backend/anastasis-httpd.h
@@ -140,11 +140,6 @@ struct TM_HandlerContext
};
/**
- * Handle to the database backend.
- */
-extern struct ANASTASIS_DatabasePlugin *db;
-
-/**
* Upload limit to the service, in megabytes.
*/
extern unsigned long long AH_upload_limit_mb;
diff --git a/src/backend/anastasis-httpd_config.c b/src/backend/anastasis-httpd_config.c
@@ -53,7 +53,6 @@ add_methods (void *cls,
return;
section += strlen ("authorization-");
p = ANASTASIS_authorization_plugin_load (section,
- db,
AH_cfg);
if (NULL == p)
{
diff --git a/src/backend/anastasis-httpd_policy-meta.c b/src/backend/anastasis-httpd_policy-meta.c
@@ -114,11 +114,11 @@ return_policy_meta (
}
result = json_object ();
GNUNET_assert (NULL != result);
- qs = db->get_recovery_meta_data (db->cls,
- account_pub,
- max_version,
- &build_meta_result,
- result);
+ qs = ANASTASIS_DB_get_recovery_meta_data (
+ account_pub,
+ max_version,
+ &build_meta_result,
+ result);
switch (qs)
{
@@ -160,11 +160,11 @@ AH_policy_meta_get (
uint32_t version;
struct GNUNET_TIME_Timestamp expiration;
- as = db->lookup_account (db->cls,
- account_pub,
- &expiration,
- &recovery_data_hash,
- &version);
+ as = ANASTASIS_DB_lookup_account (
+ account_pub,
+ &expiration,
+ &recovery_data_hash,
+ &version);
switch (as)
{
case ANASTASIS_DB_ACCOUNT_STATUS_PAYMENT_REQUIRED:
diff --git a/src/backend/anastasis-httpd_policy-upload.c b/src/backend/anastasis-httpd_policy-upload.c
@@ -364,11 +364,11 @@ proposal_cb (struct PolicyUploadContext *puc,
"Storing payment request for order `%s'\n",
por->details.ok.order_id);
- qs = db->record_recdoc_payment (db->cls,
- &puc->account,
- (uint32_t) AH_post_counter,
- &puc->payment_identifier,
- &AH_annual_fee);
+ qs = ANASTASIS_DB_record_recdoc_payment (
+ &puc->account,
+ (uint32_t) AH_post_counter,
+ &puc->payment_identifier,
+ &AH_annual_fee);
if (0 >= qs)
{
GNUNET_break (0);
@@ -474,11 +474,11 @@ check_payment_cb (struct PolicyUploadContext *puc,
paid_until = GNUNET_TIME_relative_add (paid_until,
GNUNET_TIME_UNIT_WEEKS);
- qs = db->increment_lifetime (db->cls,
- &puc->account,
- &puc->payment_identifier,
- paid_until,
- &puc->paid_until);
+ qs = ANASTASIS_DB_increment_lifetime (
+ &puc->account,
+ &puc->payment_identifier,
+ paid_until,
+ &puc->paid_until);
if (0 <= qs)
return; /* continue as planned */
GNUNET_break (0);
@@ -871,10 +871,10 @@ AH_handler_policy_post (
bool valid_counter;
enum GNUNET_DB_QueryStatus qs;
- qs = db->check_payment_identifier (db->cls,
- &puc->payment_identifier,
- &paid,
- &valid_counter);
+ qs = ANASTASIS_DB_check_payment_identifier (
+ &puc->payment_identifier,
+ &paid,
+ &valid_counter);
if (qs < 0)
return TALER_MHD_reply_with_error (puc->con,
MHD_HTTP_INTERNAL_SERVER_ERROR,
@@ -919,11 +919,11 @@ AH_handler_policy_post (
/* Cost is zero, fake "zero" payment having happened */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Policy upload is free, allowing upload without payment\n");
- qs = db->record_recdoc_payment (db->cls,
- account_pub,
- AH_post_counter,
- &puc->payment_identifier,
- &AH_annual_fee);
+ qs = ANASTASIS_DB_record_recdoc_payment (
+ account_pub,
+ AH_post_counter,
+ &puc->payment_identifier,
+ &AH_annual_fee);
if (qs <= 0)
return TALER_MHD_reply_with_error (puc->con,
MHD_HTTP_INTERNAL_SERVER_ERROR,
@@ -938,10 +938,10 @@ AH_handler_policy_post (
true),
ANASTASIS_MAX_YEARS_STORAGE);
puc->paid_until = GNUNET_TIME_relative_to_timestamp (rel);
- qs = db->update_lifetime (db->cls,
- account_pub,
- &puc->payment_identifier,
- puc->paid_until);
+ qs = ANASTASIS_DB_update_lifetime (
+ account_pub,
+ &puc->payment_identifier,
+ puc->paid_until);
if (qs <= 0)
{
GNUNET_break (0);
@@ -961,11 +961,11 @@ AH_handler_policy_post (
struct GNUNET_TIME_Timestamp now;
struct GNUNET_TIME_Relative rem;
- as = db->lookup_account (db->cls,
- account_pub,
- &puc->paid_until,
- &hash,
- &version);
+ as = ANASTASIS_DB_lookup_account (
+ account_pub,
+ &puc->paid_until,
+ &hash,
+ &version);
now = GNUNET_TIME_timestamp_get ();
if (GNUNET_TIME_timestamp_cmp (puc->paid_until,
<,
@@ -1106,16 +1106,16 @@ AH_handler_policy_post (
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Uploading recovery document\n");
- ss = db->store_recovery_document (db->cls,
- &puc->account,
- &puc->account_sig,
- &puc->new_policy_upload_hash,
- puc->upload,
- puc->upload_size,
- puc->meta_data,
- puc->meta_data_size,
- &puc->payment_identifier,
- &version);
+ ss = ANASTASIS_DB_store_recovery_document (
+ &puc->account,
+ &puc->account_sig,
+ &puc->new_policy_upload_hash,
+ puc->upload,
+ puc->upload_size,
+ puc->meta_data,
+ puc->meta_data_size,
+ &puc->payment_identifier,
+ &version);
GNUNET_snprintf (version_s,
sizeof (version_s),
"%u",
diff --git a/src/backend/anastasis-httpd_policy.c b/src/backend/anastasis-httpd_policy.c
@@ -69,23 +69,23 @@ return_policy (struct MHD_Connection *connection,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"version");
}
- qs = db->get_recovery_document (db->cls,
- account_pub,
- version,
- &account_sig,
- &recovery_data_hash,
- &res_recovery_data_size,
- &res_recovery_data);
+ qs = ANASTASIS_DB_get_recovery_document (
+ account_pub,
+ version,
+ &account_sig,
+ &recovery_data_hash,
+ &res_recovery_data_size,
+ &res_recovery_data);
}
else
{
- qs = db->get_latest_recovery_document (db->cls,
- account_pub,
- &account_sig,
- &recovery_data_hash,
- &res_recovery_data_size,
- &res_recovery_data,
- &version);
+ qs = ANASTASIS_DB_get_latest_recovery_document (
+ account_pub,
+ &account_sig,
+ &recovery_data_hash,
+ &res_recovery_data_size,
+ &res_recovery_data,
+ &version);
GNUNET_snprintf (version_b,
sizeof (version_b),
"%u",
@@ -170,11 +170,11 @@ AH_policy_get (struct MHD_Connection *connection,
uint32_t version;
struct GNUNET_TIME_Timestamp expiration;
- as = db->lookup_account (db->cls,
- account_pub,
- &expiration,
- &recovery_data_hash,
- &version);
+ as = ANASTASIS_DB_lookup_account (
+ account_pub,
+ &expiration,
+ &recovery_data_hash,
+ &version);
switch (as)
{
case ANASTASIS_DB_ACCOUNT_STATUS_PAYMENT_REQUIRED:
diff --git a/src/backend/anastasis-httpd_truth-challenge.c b/src/backend/anastasis-httpd_truth-challenge.c
@@ -388,9 +388,9 @@ refund_cb (
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Refund `%s' succeeded\n",
re->order_id);
- qs = db->record_challenge_refund (db->cls,
- &re->truth_uuid,
- &re->payment_identifier);
+ qs = ANASTASIS_DB_record_challenge_refund (
+ &re->truth_uuid,
+ &re->payment_identifier);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
@@ -640,10 +640,10 @@ proposal_cb (struct ChallengeContext *gc,
gc->response_code = MHD_HTTP_BAD_GATEWAY;
return;
}
- qs = db->record_challenge_payment (db->cls,
- &gc->truth_uuid,
- &gc->payment_identifier,
- &gc->challenge_cost);
+ qs = ANASTASIS_DB_record_challenge_payment (
+ &gc->truth_uuid,
+ &gc->payment_identifier,
+ &gc->challenge_cost);
if (0 >= qs)
{
GNUNET_break (0);
@@ -730,9 +730,9 @@ check_payment_cb (struct ChallengeContext *gc,
{
enum GNUNET_DB_QueryStatus qs;
- qs = db->update_challenge_payment (db->cls,
- &gc->truth_uuid,
- &gc->payment_identifier);
+ qs = ANASTASIS_DB_update_challenge_payment (
+ &gc->truth_uuid,
+ &gc->payment_identifier);
if (0 <= qs)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -773,9 +773,9 @@ begin_payment (struct ChallengeContext *gc)
enum GNUNET_DB_QueryStatus qs;
char *order_id;
- qs = db->lookup_challenge_payment (db->cls,
- &gc->truth_uuid,
- &gc->payment_identifier);
+ qs = ANASTASIS_DB_lookup_challenge_payment (
+ &gc->truth_uuid,
+ &gc->payment_identifier);
if (qs < 0)
{
GNUNET_break (0);
@@ -938,10 +938,10 @@ run_authorization_process (struct MHD_Connection *connection,
"Authorization request %llu for %s sent successfully\n",
(unsigned long long) gc->code,
TALER_B2S (&gc->truth_uuid));
- qs = db->mark_challenge_sent (db->cls,
- &gc->payment_identifier,
- &gc->truth_uuid,
- gc->code);
+ qs = ANASTASIS_DB_mark_challenge_sent (
+ &gc->payment_identifier,
+ &gc->truth_uuid,
+ gc->code);
GNUNET_break (0 < qs);
gc->authorization->cleanup (gc->as);
gc->as = NULL;
@@ -960,10 +960,10 @@ run_authorization_process (struct MHD_Connection *connection,
return MHD_YES;
case ANASTASIS_AUTHORIZATION_CRES_SUCCESS_REPLY_FAILED:
/* Challenge sent successfully */
- qs = db->mark_challenge_sent (db->cls,
- &gc->payment_identifier,
- &gc->truth_uuid,
- gc->code);
+ qs = ANASTASIS_DB_mark_challenge_sent (
+ &gc->payment_identifier,
+ &gc->truth_uuid,
+ gc->code);
GNUNET_break (0 < qs);
gc->authorization->cleanup (gc->as);
gc->as = NULL;
@@ -1099,12 +1099,12 @@ AH_handler_truth_challenge (
enum GNUNET_DB_QueryStatus qs;
char *method;
- qs = db->get_escrow_challenge (db->cls,
- &gc->truth_uuid,
- &encrypted_truth,
- &encrypted_truth_size,
- &truth_mime,
- &method);
+ qs = ANASTASIS_DB_get_escrow_challenge (
+ &gc->truth_uuid,
+ &encrypted_truth,
+ &encrypted_truth_size,
+ &truth_mime,
+ &method);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
@@ -1137,7 +1137,6 @@ AH_handler_truth_challenge (
gc->authorization
= ANASTASIS_authorization_plugin_load (method,
- db,
AH_cfg);
if (NULL == gc->authorization)
{
@@ -1189,10 +1188,10 @@ AH_handler_truth_challenge (
"Beginning payment, client did not provide payment identifier\n");
return begin_payment (gc);
}
- qs = db->check_challenge_payment (db->cls,
- &gc->payment_identifier,
- &gc->truth_uuid,
- &paid);
+ qs = ANASTASIS_DB_check_challenge_payment (
+ &gc->payment_identifier,
+ &gc->truth_uuid,
+ &paid);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
@@ -1285,13 +1284,13 @@ AH_handler_truth_challenge (
struct GNUNET_TIME_Timestamp transmission_date;
enum GNUNET_DB_QueryStatus qs;
- qs = db->create_challenge_code (db->cls,
- &gc->truth_uuid,
- gc->authorization->code_rotation_period,
- gc->authorization->code_validity_period,
- gc->authorization->retry_counter,
- &transmission_date,
- &gc->code);
+ qs = ANASTASIS_DB_create_challenge_code (
+ &gc->truth_uuid,
+ gc->authorization->code_rotation_period,
+ gc->authorization->code_validity_period,
+ gc->authorization->retry_counter,
+ &transmission_date,
+ &gc->code);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
diff --git a/src/backend/anastasis-httpd_truth-solve.c b/src/backend/anastasis-httpd_truth-solve.c
@@ -475,10 +475,10 @@ proposal_cb (struct SolveContext *gc,
gc->response_code = MHD_HTTP_BAD_GATEWAY;
return;
}
- qs = db->record_challenge_payment (db->cls,
- &gc->truth_uuid,
- &gc->payment_identifier,
- &gc->challenge_cost);
+ qs = ANASTASIS_DB_record_challenge_payment (
+ &gc->truth_uuid,
+ &gc->payment_identifier,
+ &gc->challenge_cost);
if (0 >= qs)
{
GNUNET_break (0);
@@ -565,9 +565,9 @@ check_payment_cb (struct SolveContext *gc,
{
enum GNUNET_DB_QueryStatus qs;
- qs = db->update_challenge_payment (db->cls,
- &gc->truth_uuid,
- &gc->payment_identifier);
+ qs = ANASTASIS_DB_update_challenge_payment (
+ &gc->truth_uuid,
+ &gc->payment_identifier);
if (0 <= qs)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -608,9 +608,9 @@ begin_payment (struct SolveContext *gc)
enum GNUNET_DB_QueryStatus qs;
char *order_id;
- qs = db->lookup_challenge_payment (db->cls,
- &gc->truth_uuid,
- &gc->payment_identifier);
+ qs = ANASTASIS_DB_lookup_challenge_payment (
+ &gc->truth_uuid,
+ &gc->payment_identifier);
if (qs < 0)
{
GNUNET_break (0);
@@ -726,9 +726,9 @@ return_key_share (
{
enum GNUNET_DB_QueryStatus qs;
- qs = db->get_key_share (db->cls,
- truth_uuid,
- &encrypted_keyshare);
+ qs = ANASTASIS_DB_get_key_share (
+ truth_uuid,
+ &encrypted_keyshare);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
@@ -888,13 +888,13 @@ rate_limit (struct SolveContext *gc)
uint64_t dummy;
rt = GNUNET_TIME_UNIT_FOREVER_TS;
- qs = db->create_challenge_code (db->cls,
- &gc->truth_uuid,
- MAX_QUESTION_FREQ,
- GNUNET_TIME_UNIT_HOURS,
- INITIAL_RETRY_COUNTER,
- &rt,
- &code);
+ qs = ANASTASIS_DB_create_challenge_code (
+ &gc->truth_uuid,
+ MAX_QUESTION_FREQ,
+ GNUNET_TIME_UNIT_HOURS,
+ INITIAL_RETRY_COUNTER,
+ &rt,
+ &code);
if (0 > qs)
{
GNUNET_break (0 < qs);
@@ -918,11 +918,11 @@ rate_limit (struct SolveContext *gc)
/* decrement trial counter */
ANASTASIS_hash_answer (code + 1, /* always use wrong answer */
&hc);
- cs = db->verify_challenge_code (db->cls,
- &gc->truth_uuid,
- &hc,
- &dummy,
- &satisfied);
+ cs = ANASTASIS_DB_verify_challenge_code (
+ &gc->truth_uuid,
+ &hc,
+ &dummy,
+ &satisfied);
switch (cs)
{
case ANASTASIS_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH:
@@ -1258,12 +1258,12 @@ AH_handler_truth_solve (
enum GNUNET_DB_QueryStatus qs;
char *method;
- qs = db->get_escrow_challenge (db->cls,
- &gc->truth_uuid,
- &encrypted_truth,
- &encrypted_truth_size,
- &truth_mime,
- &method);
+ qs = ANASTASIS_DB_get_escrow_challenge (
+ &gc->truth_uuid,
+ &encrypted_truth,
+ &encrypted_truth_size,
+ &truth_mime,
+ &method);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
@@ -1287,7 +1287,6 @@ AH_handler_truth_solve (
{
gc->authorization
= ANASTASIS_authorization_plugin_load (method,
- db,
AH_cfg);
if (NULL == gc->authorization)
{
@@ -1330,10 +1329,10 @@ AH_handler_truth_solve (
"Beginning payment, client did not provide payment identifier\n");
return begin_payment (gc);
}
- qs = db->check_challenge_payment (db->cls,
- &gc->payment_identifier,
- &gc->truth_uuid,
- &paid);
+ qs = ANASTASIS_DB_check_challenge_payment (
+ &gc->payment_identifier,
+ &gc->truth_uuid,
+ &paid);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
@@ -1435,11 +1434,11 @@ AH_handler_truth_solve (
}
/* random code, check against database */
- cs = db->verify_challenge_code (db->cls,
- &gc->truth_uuid,
- &gc->challenge_response,
- &code,
- &satisfied);
+ cs = ANASTASIS_DB_verify_challenge_code (
+ &gc->truth_uuid,
+ &gc->challenge_response,
+ &code,
+ &satisfied);
switch (cs)
{
case ANASTASIS_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH:
diff --git a/src/backend/anastasis-httpd_truth-upload.c b/src/backend/anastasis-httpd_truth-upload.c
@@ -357,8 +357,7 @@ check_payment_cb (struct TruthUploadContext *tuc,
with 365 days. */
paid_until = GNUNET_TIME_relative_add (paid_until,
GNUNET_TIME_UNIT_WEEKS);
- qs = db->record_truth_upload_payment (
- db->cls,
+ qs = ANASTASIS_DB_record_truth_upload_payment (
&tuc->truth_uuid,
&osr->details.ok.details.paid.deposit_total,
paid_until);
@@ -623,7 +622,6 @@ AH_handler_truth_post (
type)) &&
(NULL ==
ANASTASIS_authorization_plugin_load (type,
- db,
AH_cfg)) )
{
GNUNET_JSON_parse_free (spec);
@@ -653,9 +651,9 @@ AH_handler_truth_post (
= GNUNET_TIME_relative_to_timestamp (
GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_YEARS,
storage_years));
- qs = db->check_truth_upload_paid (db->cls,
- truth_uuid,
- &paid_until);
+ qs = ANASTASIS_DB_check_truth_upload_paid (
+ truth_uuid,
+ &paid_until);
if (qs < 0)
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
@@ -719,17 +717,17 @@ AH_handler_truth_post (
{
enum GNUNET_DB_QueryStatus qs;
- qs = db->store_truth (db->cls,
- truth_uuid,
- &key_share_data,
- (NULL == truth_mime)
+ qs = ANASTASIS_DB_store_truth (
+ truth_uuid,
+ &key_share_data,
+ (NULL == truth_mime)
? ""
: truth_mime,
- encrypted_truth,
- encrypted_truth_size,
- type,
- GNUNET_TIME_absolute_get_remaining (
- paid_until.abs_time));
+ encrypted_truth,
+ encrypted_truth_size,
+ type,
+ GNUNET_TIME_absolute_get_remaining (
+ paid_until.abs_time));
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
@@ -749,12 +747,12 @@ AH_handler_truth_post (
bool ok = false;
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
- db->get_escrow_challenge (db->cls,
- truth_uuid,
- &xtruth,
- &xtruth_size,
- &xtruth_mime,
- &xmethod))
+ ANASTASIS_DB_get_escrow_challenge (
+ truth_uuid,
+ &xtruth,
+ &xtruth_size,
+ &xtruth_mime,
+ &xmethod))
{
ok = ( (xtruth_size == encrypted_truth_size) &&
(0 == strcmp (xmethod,
diff --git a/src/include/anastasis/anastasis-database/challenge_gc.h b/src/include/anastasis/anastasis-database/challenge_gc.h
@@ -0,0 +1,37 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/challenge_gc.h
+ * @brief Anastasis database: challenge gc
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_CHALLENGE_GC_H
+#define ANASTASIS_DATABASE_CHALLENGE_GC_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Function called to remove all expired codes from the database.
+ *
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_challenge_gc (void);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/check_challenge_payment.h b/src/include/anastasis/anastasis-database/check_challenge_payment.h
@@ -0,0 +1,44 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/check_challenge_payment.h
+ * @brief Anastasis database: check challenge payment
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_CHECK_CHALLENGE_PAYMENT_H
+#define ANASTASIS_DATABASE_CHECK_CHALLENGE_PAYMENT_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Check payment identifier. Used to check if a payment identifier given by
+ * the user is valid (existing and paid).
+ *
+ * @param payment_secret payment secret which the user must provide with every upload
+ * @param truth_uuid which truth should we check the payment status of
+ * @param[out] paid bool value to show if payment is paid
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_check_challenge_payment (
+ const struct ANASTASIS_PaymentSecretP *payment_secret,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ bool *paid);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/check_payment_identifier.h b/src/include/anastasis/anastasis-database/check_payment_identifier.h
@@ -0,0 +1,44 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/check_payment_identifier.h
+ * @brief Anastasis database: check payment identifier
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_CHECK_PAYMENT_IDENTIFIER_H
+#define ANASTASIS_DATABASE_CHECK_PAYMENT_IDENTIFIER_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Check payment identifier. Used to check if a payment identifier given by
+ * the user is valid (existing and paid).
+ *
+ * @param payment_secret payment secret which the user must provide with every upload
+ * @param[out] paid bool value to show if payment is paid
+ * @param[out] valid_counter bool value to show if post_counter is > 0
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_check_payment_identifier (
+ const struct ANASTASIS_PaymentSecretP *payment_secret,
+ bool *paid,
+ bool *valid_counter);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/check_truth_upload_paid.h b/src/include/anastasis/anastasis-database/check_truth_upload_paid.h
@@ -0,0 +1,41 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/check_truth_upload_paid.h
+ * @brief Anastasis database: check truth upload paid
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_CHECK_TRUTH_UPLOAD_PAID_H
+#define ANASTASIS_DATABASE_CHECK_TRUTH_UPLOAD_PAID_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Inquire whether truth upload payment was made.
+ *
+ * @param uuid the truth's UUID
+ * @param[out] paid_until set for how long this truth is paid for
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_check_truth_upload_paid (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid,
+ struct GNUNET_TIME_Timestamp *paid_until);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/common.h b/src/include/anastasis/anastasis-database/common.h
@@ -0,0 +1,180 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2019-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/common.h
+ * @brief common definitions for the Anastasis database
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_COMMON_H
+#define ANASTASIS_DATABASE_COMMON_H
+
+#include "anastasis_service.h"
+#include <gnunet/gnunet_db_lib.h>
+
+/**
+ * How long is an offer for a challenge payment valid for payment?
+ */
+#define ANASTASIS_CHALLENGE_OFFER_LIFETIME GNUNET_TIME_UNIT_HOURS
+
+/**
+ * Return values for checking code validity.
+ */
+enum ANASTASIS_DB_CodeStatus
+{
+ /**
+ * Provided authentication code does not match database content.
+ */
+ ANASTASIS_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH = -3,
+
+ /**
+ * Encountered hard error talking to DB.
+ */
+ ANASTASIS_DB_CODE_STATUS_HARD_ERROR = -2,
+
+ /**
+ * Encountered serialization error talking to DB.
+ */
+ ANASTASIS_DB_CODE_STATUS_SOFT_ERROR = -1,
+
+ /**
+ * We have no challenge in the database.
+ */
+ ANASTASIS_DB_CODE_STATUS_NO_RESULTS = 0,
+
+ /**
+ * The provided challenge matches what we have in the database.
+ */
+ ANASTASIS_DB_CODE_STATUS_VALID_CODE_STORED = 1,
+};
+
+
+/**
+ * Return values for checking account validity.
+ */
+enum ANASTASIS_DB_AccountStatus
+{
+ /**
+ * Account is unknown, user should pay to establish it.
+ */
+ ANASTASIS_DB_ACCOUNT_STATUS_PAYMENT_REQUIRED = -3,
+
+ /**
+ * Encountered hard error talking to DB.
+ */
+ ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR = -2,
+
+ /**
+ * Account is valid, but we have no policy stored yet.
+ */
+ ANASTASIS_DB_ACCOUNT_STATUS_NO_RESULTS = 0,
+
+ /**
+ * Account is valid, and we have a policy stored.
+ */
+ ANASTASIS_DB_ACCOUNT_STATUS_VALID_HASH_RETURNED = 1,
+};
+
+
+/**
+ * Return values for storing data in database with payment.
+ */
+enum ANASTASIS_DB_StoreStatus
+{
+ /**
+ * The client has stored too many policies, should pay to store more.
+ */
+ ANASTASIS_DB_STORE_STATUS_STORE_LIMIT_EXCEEDED = -4,
+
+ /**
+ * The client needs to pay to store policies.
+ */
+ ANASTASIS_DB_STORE_STATUS_PAYMENT_REQUIRED = -3,
+
+ /**
+ * Encountered hard error talking to DB.
+ */
+ ANASTASIS_DB_STORE_STATUS_HARD_ERROR = -2,
+
+ /**
+ * Despite retrying, we encountered serialization errors.
+ */
+ ANASTASIS_DB_STORE_STATUS_SOFT_ERROR = -1,
+
+ /**
+ * Database did not need an update (document exists).
+ */
+ ANASTASIS_DB_STORE_STATUS_NO_RESULTS = 0,
+
+ /**
+ * We successfully stored the document.
+ */
+ ANASTASIS_DB_STORE_STATUS_SUCCESS = 1,
+};
+
+
+/**
+ * Function called on all pending payments for an account or challenge.
+ *
+ * @param cls closure
+ * @param timestamp for how long have we been waiting
+ * @param payment_secret payment secret / order id in the backend
+ * @param amount how much is the order for
+ */
+typedef void
+(*ANASTASIS_DB_PaymentPendingIterator)(
+ void *cls,
+ struct GNUNET_TIME_Timestamp timestamp,
+ const struct ANASTASIS_PaymentSecretP *payment_secret,
+ const struct TALER_Amount *amount);
+
+
+/**
+ * Function called to test if a given wire transfer
+ * satisfied the authentication requirement of the
+ * IBAN plugin.
+ *
+ * @param cls closure
+ * @param credit amount that was transferred
+ * @param wire_subject subject provided in the wire transfer
+ * @return true if this wire transfer satisfied the authentication check
+ */
+typedef bool
+(*ANASTASIS_DB_AuthIbanTransfercheck)(
+ void *cls,
+ const struct TALER_Amount *credit,
+ const char *wire_subject);
+
+
+/**
+ * Function called on matching meta data. Note that if the client did
+ * not provide meta data for @a version, the function will be called
+ * with @a recovery_meta_data being NULL.
+ *
+ * @param cls closure
+ * @param version the version of the recovery document
+ * @param ts timestamp when the document was uploaded
+ * @param recovery_meta_data contains meta data about the encrypted recovery document
+ * @param recovery_meta_data_size size of @a recovery_meta_data blob
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_NO to abort iteration
+ */
+typedef enum GNUNET_GenericReturnValue
+(*ANASTASIS_DB_RecoveryMetaCallback)(void *cls,
+ uint32_t version,
+ struct GNUNET_TIME_Timestamp ts,
+ const void *recovery_meta_data,
+ size_t recovery_meta_data_size);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/create_challenge_code.h b/src/include/anastasis/anastasis-database/create_challenge_code.h
@@ -0,0 +1,53 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/create_challenge_code.h
+ * @brief Anastasis database: create challenge code
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_CREATE_CHALLENGE_CODE_H
+#define ANASTASIS_DATABASE_CREATE_CHALLENGE_CODE_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Create a new 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.
+ *
+ * @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 retry_counter amount of retries allowed
+ * @param[out] retransmission_date when to next retransmit
+ * @param[out] code set to the code which will be checked for later
+ * @return transaction status,
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if we are out of valid tries,
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a code is now in the DB
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_create_challenge_code (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ struct GNUNET_TIME_Relative rotation_period,
+ struct GNUNET_TIME_Relative validity_period,
+ uint32_t retry_counter,
+ struct GNUNET_TIME_Timestamp *retransmission_date,
+ uint64_t *code);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/create_tables.h b/src/include/anastasis/anastasis-database/create_tables.h
@@ -0,0 +1,34 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/create_tables.h
+ * @brief create the Anastasis database tables
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_CREATE_TABLES_H
+#define ANASTASIS_DATABASE_CREATE_TABLES_H
+
+#include <gnunet/gnunet_util_lib.h>
+
+/**
+ * Initialize the database tables.
+ *
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+enum GNUNET_GenericReturnValue
+ANASTASIS_DB_create_tables (void);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/drop_tables.h b/src/include/anastasis/anastasis-database/drop_tables.h
@@ -0,0 +1,34 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/drop_tables.h
+ * @brief drop the Anastasis database tables
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_DROP_TABLES_H
+#define ANASTASIS_DATABASE_DROP_TABLES_H
+
+#include <gnunet/gnunet_util_lib.h>
+
+/**
+ * Drop the Anastasis tables. Used for testcases.
+ *
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+enum GNUNET_GenericReturnValue
+ANASTASIS_DB_drop_tables (void);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/event.h b/src/include/anastasis/anastasis-database/event.h
@@ -0,0 +1,65 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/event.h
+ * @brief database event (notification) support for Anastasis
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_EVENT_H
+#define ANASTASIS_DATABASE_EVENT_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+
+/**
+ * Register callback to be invoked on events of type @a es.
+ *
+ * @param es specification of the event to listen for
+ * @param timeout how long to wait for the event
+ * @param cb function to call when the event happens, possibly
+ * multiple times (until cancel is invoked)
+ * @param cb_cls closure for @a cb
+ * @return handle useful to cancel the listener
+ */
+struct GNUNET_DB_EventHandler *
+ANASTASIS_DB_event_listen (const struct GNUNET_DB_EventHeaderP *es,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_DB_EventCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Stop notifications.
+ *
+ * @param eh handle to unregister.
+ */
+void
+ANASTASIS_DB_event_listen_cancel (struct GNUNET_DB_EventHandler *eh);
+
+
+/**
+ * Notify all that listen on @a es of an event.
+ *
+ * @param es specification of the event to generate
+ * @param extra additional event data provided
+ * @param extra_size number of bytes in @a extra
+ */
+void
+ANASTASIS_DB_event_notify (const struct GNUNET_DB_EventHeaderP *es,
+ const void *extra,
+ size_t extra_size);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/gc.h b/src/include/anastasis/anastasis-database/gc.h
@@ -0,0 +1,43 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/gc.h
+ * @brief garbage collection for the Anastasis database
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_GC_H
+#define ANASTASIS_DATABASE_GC_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+
+/**
+ * Function called to perform "garbage collection" on the
+ * database, expiring records we no longer require. Deletes
+ * all user records that are not paid up (and by cascade deletes
+ * the associated recovery documents). Also deletes expired
+ * truth and financial records older than @a expire_pending_payments.
+ *
+ * @param expire_backups backups older than the given time stamp should be garbage collected
+ * @param expire_pending_payments payments still pending from since before
+ * this value should be garbage collected
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_gc (struct GNUNET_TIME_Absolute expire_backups,
+ struct GNUNET_TIME_Absolute expire_pending_payments);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/get_escrow_challenge.h b/src/include/anastasis/anastasis-database/get_escrow_challenge.h
@@ -0,0 +1,47 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/get_escrow_challenge.h
+ * @brief Anastasis database: get escrow challenge
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_GET_ESCROW_CHALLENGE_H
+#define ANASTASIS_DATABASE_GET_ESCROW_CHALLENGE_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Get the encrypted truth to validate the challenge response
+ *
+ * @param truth_uuid the identifier for the Truth
+ * @param[out] truth contains the encrypted truth
+ * @param[out] truth_size size of the encrypted truth
+ * @param[out] truth_mime mime type of truth
+ * @param[out] method type of the challenge
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_get_escrow_challenge (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ void **truth,
+ size_t *truth_size,
+ char **truth_mime,
+ char **method);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/get_key_share.h b/src/include/anastasis/anastasis-database/get_key_share.h
@@ -0,0 +1,41 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/get_key_share.h
+ * @brief Anastasis database: get key share
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_GET_KEY_SHARE_H
+#define ANASTASIS_DATABASE_GET_KEY_SHARE_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Lookup (encrypted) key share by @a truth_uuid.
+ *
+ * @param truth_uuid the identifier for the Truth
+ * @param[out] key_share contains the encrypted Keyshare
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_get_key_share (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ struct ANASTASIS_CRYPTO_EncryptedKeyShareP *key_share);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/get_last_auth_iban_payment_row.h b/src/include/anastasis/anastasis-database/get_last_auth_iban_payment_row.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/get_last_auth_iban_payment_row.h
+ * @brief Anastasis database: get last auth iban payment row
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_GET_LAST_AUTH_IBAN_PAYMENT_ROW_H
+#define ANASTASIS_DATABASE_GET_LAST_AUTH_IBAN_PAYMENT_ROW_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Function to check the last known IBAN payment.
+ *
+ * @param credit_account which credit account to check
+ * @param[out] last_row set to the last known row
+ * @return transaction status,
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a cb
+ * returned 'true' once
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if no
+ * wire transfers existed for which @a cb returned true
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_get_last_auth_iban_payment_row (
+ const char *credit_account,
+ uint64_t *last_row);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/get_latest_recovery_document.h b/src/include/anastasis/anastasis-database/get_latest_recovery_document.h
@@ -0,0 +1,49 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/get_latest_recovery_document.h
+ * @brief Anastasis database: get latest recovery document
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_GET_LATEST_RECOVERY_DOCUMENT_H
+#define ANASTASIS_DATABASE_GET_LATEST_RECOVERY_DOCUMENT_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Fetch latest recovery document for user.
+ *
+ * @param account_pub public key of the user's account
+ * @param account_sig signature
+ * @param recovery_data_hash hash of the current recovery data
+ * @param data_size size of data blob
+ * @param data blob which contains the recovery document
+ * @param[out] version set to the version number of the policy being returned
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_get_latest_recovery_document (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ struct ANASTASIS_AccountSignatureP *account_sig,
+ struct GNUNET_HashCode *recovery_data_hash,
+ size_t *data_size,
+ void **data,
+ uint32_t *version);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/get_recovery_document.h b/src/include/anastasis/anastasis-database/get_recovery_document.h
@@ -0,0 +1,49 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/get_recovery_document.h
+ * @brief Anastasis database: get recovery document
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_GET_RECOVERY_DOCUMENT_H
+#define ANASTASIS_DATABASE_GET_RECOVERY_DOCUMENT_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Fetch recovery document for user according given version.
+ *
+ * @param account_pub public key of the user's account
+ * @param version the version number of the policy the user requests
+ * @param[out] account_sig signature
+ * @param[out] recovery_data_hash hash of the current recovery data
+ * @param[out] data_size size of data blob
+ * @param[out] data blob which contains the recovery document
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_get_recovery_document (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ uint32_t version,
+ struct ANASTASIS_AccountSignatureP *account_sig,
+ struct GNUNET_HashCode *recovery_data_hash,
+ size_t *data_size,
+ void **data);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/get_recovery_meta_data.h b/src/include/anastasis/anastasis-database/get_recovery_meta_data.h
@@ -0,0 +1,39 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/get_recovery_meta_data.h
+ * @brief Anastasis database: get recovery meta data
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_GET_RECOVERY_META_DATA_H
+#define ANASTASIS_DATABASE_GET_RECOVERY_META_DATA_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Closure for meta_iterator().
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_get_recovery_meta_data (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ uint32_t max_version,
+ ANASTASIS_DB_RecoveryMetaCallback cb,
+ void *cb_cls);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/increment_lifetime.h b/src/include/anastasis/anastasis-database/increment_lifetime.h
@@ -0,0 +1,46 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/increment_lifetime.h
+ * @brief Anastasis database: increment lifetime
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_INCREMENT_LIFETIME_H
+#define ANASTASIS_DATABASE_INCREMENT_LIFETIME_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Increment account lifetime based on payment having been received.
+ * Does nothing if the payment is not new.
+ *
+ * @param account_pub which account received a payment
+ * @param payment_identifier proof of payment, must be unique and match pending payment
+ * @param lifetime for how long is the account now paid (increment)
+ * @param[out] paid_until set to the end of the lifetime after the operation
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_increment_lifetime (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ const struct ANASTASIS_PaymentSecretP *payment_identifier,
+ struct GNUNET_TIME_Relative lifetime,
+ struct GNUNET_TIME_Timestamp *paid_until);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/lookup_account.h b/src/include/anastasis/anastasis-database/lookup_account.h
@@ -0,0 +1,46 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/lookup_account.h
+ * @brief Anastasis database: lookup account
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_LOOKUP_ACCOUNT_H
+#define ANASTASIS_DATABASE_LOOKUP_ACCOUNT_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Check if an account exists, and if so, return the
+ * current @a recovery_document_hash.
+ *
+ * @param account_pub account identifier
+ * @param[out] paid_until until when is the account paid up?
+ * @param[out] recovery_data_hash set to hash of @a recovery document
+ * @param[out] version set to the recovery policy version
+ * @return transaction status
+ */
+enum ANASTASIS_DB_AccountStatus
+ANASTASIS_DB_lookup_account (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ struct GNUNET_TIME_Timestamp *paid_until,
+ struct GNUNET_HashCode *recovery_data_hash,
+ uint32_t *version);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/lookup_challenge_payment.h b/src/include/anastasis/anastasis-database/lookup_challenge_payment.h
@@ -0,0 +1,41 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/lookup_challenge_payment.h
+ * @brief Anastasis database: lookup challenge payment
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_LOOKUP_CHALLENGE_PAYMENT_H
+#define ANASTASIS_DATABASE_LOOKUP_CHALLENGE_PAYMENT_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Lookup pending payment for a certain challenge.
+ *
+ * @param truth_uuid identification of the challenge
+ * @param[out] payment_secret set to the challenge payment secret
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_lookup_challenge_payment (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ struct ANASTASIS_PaymentSecretP *payment_secret);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/mark_challenge_code_satisfied.h b/src/include/anastasis/anastasis-database/mark_challenge_code_satisfied.h
@@ -0,0 +1,42 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/mark_challenge_code_satisfied.h
+ * @brief Anastasis database: mark challenge code satisfied
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_MARK_CHALLENGE_CODE_SATISFIED_H
+#define ANASTASIS_DATABASE_MARK_CHALLENGE_CODE_SATISFIED_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Set the 'satisfied' bit for the given challenge and code to
+ * 'true'.
+ *
+ * @param truth_uuid identification of the challenge which the code corresponds to
+ * @param code code which is now satisfied
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_mark_challenge_code_satisfied (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const uint64_t code);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/mark_challenge_sent.h b/src/include/anastasis/anastasis-database/mark_challenge_sent.h
@@ -0,0 +1,42 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/mark_challenge_sent.h
+ * @brief Anastasis database: mark challenge sent
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_MARK_CHALLENGE_SENT_H
+#define ANASTASIS_DATABASE_MARK_CHALLENGE_SENT_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Remember in the database that we successfully sent a challenge.
+ *
+ * @param payment_secret payment secret which the user must provide with every upload
+ * @param truth_uuid the identifier for the challenge
+ * @param code the challenge that was sent
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_mark_challenge_sent (
+ const struct ANASTASIS_PaymentSecretP *payment_secret,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ uint64_t code);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/preflight.h b/src/include/anastasis/anastasis-database/preflight.h
@@ -0,0 +1,38 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/preflight.h
+ * @brief preflight check for the Anastasis database
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_PREFLIGHT_H
+#define ANASTASIS_DATABASE_PREFLIGHT_H
+
+#include <gnunet/gnunet_util_lib.h>
+
+/**
+ * Do a pre-flight check that we are not in an uncommitted transaction.
+ * If we are, try to commit the previous transaction and output a warning.
+ * Does not return anything, as we will continue regardless of the outcome.
+ *
+ * @return #GNUNET_OK if everything is fine
+ * #GNUNET_NO if a transaction was rolled back
+ * #GNUNET_SYSERR on hard errors
+ */
+enum GNUNET_GenericReturnValue
+ANASTASIS_DB_preflight (void);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/record_auth_iban_payment.h b/src/include/anastasis/anastasis-database/record_auth_iban_payment.h
@@ -0,0 +1,49 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/record_auth_iban_payment.h
+ * @brief Anastasis database: record auth iban payment
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_RECORD_AUTH_IBAN_PAYMENT_H
+#define ANASTASIS_DATABASE_RECORD_AUTH_IBAN_PAYMENT_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Store inbound IBAN payment made for authentication.
+ *
+ * @param wire_reference unique identifier inside LibEuFin/Nexus
+ * @param wire_subject subject of the wire transfer
+ * @param amount how much was transferred
+ * @param debit_account account that was debited
+ * @param credit_account Anastasis operator account credited
+ * @param execution_date when was the transfer made
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_record_auth_iban_payment (
+ uint64_t wire_reference,
+ const char *wire_subject,
+ const struct TALER_Amount *amount,
+ const char *debit_account,
+ const char *credit_account,
+ struct GNUNET_TIME_Timestamp execution_date);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/record_challenge_payment.h b/src/include/anastasis/anastasis-database/record_challenge_payment.h
@@ -0,0 +1,43 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/record_challenge_payment.h
+ * @brief Anastasis database: record challenge payment
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_RECORD_CHALLENGE_PAYMENT_H
+#define ANASTASIS_DATABASE_RECORD_CHALLENGE_PAYMENT_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Store payment for challenge.
+ *
+ * @param truth_uuid identifier of the challenge to pay
+ * @param payment_secret payment secret which the user must provide with every upload
+ * @param amount how much we asked for
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_record_challenge_payment (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const struct ANASTASIS_PaymentSecretP *payment_secret,
+ const struct TALER_Amount *amount);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/record_challenge_refund.h b/src/include/anastasis/anastasis-database/record_challenge_refund.h
@@ -0,0 +1,41 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/record_challenge_refund.h
+ * @brief Anastasis database: record challenge refund
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_RECORD_CHALLENGE_REFUND_H
+#define ANASTASIS_DATABASE_RECORD_CHALLENGE_REFUND_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Store refund granted for challenge.
+ *
+ * @param truth_uuid identifier of the challenge to refund
+ * @param payment_secret payment secret which the user must provide with every upload
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_record_challenge_refund (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const struct ANASTASIS_PaymentSecretP *payment_secret);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/record_recdoc_payment.h b/src/include/anastasis/anastasis-database/record_recdoc_payment.h
@@ -0,0 +1,47 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/record_recdoc_payment.h
+ * @brief Anastasis database: record recdoc payment
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_RECORD_RECDOC_PAYMENT_H
+#define ANASTASIS_DATABASE_RECORD_RECDOC_PAYMENT_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Store payment. Used to begin a payment, not indicative
+ * that the payment actually was made. (That is done
+ * when we increment the account's lifetime.)
+ *
+ * @param account_pub anastasis's public key
+ * @param post_counter how many uploads does @a amount pay for
+ * @param payment_secret payment secret which the user must provide with every upload
+ * @param amount how much we asked for
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_record_recdoc_payment (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ uint32_t post_counter,
+ const struct ANASTASIS_PaymentSecretP *payment_secret,
+ const struct TALER_Amount *amount);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/record_truth_upload_payment.h b/src/include/anastasis/anastasis-database/record_truth_upload_payment.h
@@ -0,0 +1,43 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/record_truth_upload_payment.h
+ * @brief Anastasis database: record truth upload payment
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_RECORD_TRUTH_UPLOAD_PAYMENT_H
+#define ANASTASIS_DATABASE_RECORD_TRUTH_UPLOAD_PAYMENT_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Record truth upload payment was made.
+ *
+ * @param uuid the truth's UUID
+ * @param amount the amount that was paid
+ * @param duration how long is the truth paid for
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_record_truth_upload_payment (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid,
+ const struct TALER_Amount *amount,
+ struct GNUNET_TIME_Relative duration);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/store_recovery_document.h b/src/include/anastasis/anastasis-database/store_recovery_document.h
@@ -0,0 +1,54 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/store_recovery_document.h
+ * @brief Anastasis database: store recovery document
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_STORE_RECOVERY_DOCUMENT_H
+#define ANASTASIS_DATABASE_STORE_RECOVERY_DOCUMENT_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Store encrypted recovery document.
+ *
+ * @param account_pub public key of the user's account
+ * @param account_sig signature affirming storage request
+ * @param recovery_data_hash hash of @a data
+ * @param recovery_data contains encrypted_recovery_document
+ * @param recovery_data_size size of data blob
+ * @param payment_secret identifier for the payment, used to later charge on uploads
+ * @param[out] version set to the version assigned to the document by the database
+ * @return transaction status, 0 if upload could not be finished because @a payment_secret
+ * did not have enough upload left; HARD error if @a payment_secret is unknown, ...
+ */
+enum ANASTASIS_DB_StoreStatus
+ANASTASIS_DB_store_recovery_document (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ const struct ANASTASIS_AccountSignatureP *account_sig,
+ 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);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/store_truth.h b/src/include/anastasis/anastasis-database/store_truth.h
@@ -0,0 +1,51 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/store_truth.h
+ * @brief Anastasis database: store truth
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_STORE_TRUTH_H
+#define ANASTASIS_DATABASE_STORE_TRUTH_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Upload Truth, which contains the Truth and the KeyShare.
+ *
+ * @param truth_uuid the identifier for the Truth
+ * @param key_share_data contains information of an EncryptedKeyShare
+ * @param mime_type presumed mime type of data in @a encrypted_truth
+ * @param encrypted_truth contains the encrypted Truth which includes the ground truth i.e. H(challenge answer), phonenumber, SMS
+ * @param encrypted_truth_size the size of the Truth
+ * @param method name of method
+ * @param truth_expiration time till the according data will be stored
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_store_truth (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const struct ANASTASIS_CRYPTO_EncryptedKeyShareP *key_share_data,
+ const char *mime_type,
+ const void *encrypted_truth,
+ size_t encrypted_truth_size,
+ const char *method,
+ struct GNUNET_TIME_Relative truth_expiration);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/test_auth_iban_payment.h b/src/include/anastasis/anastasis-database/test_auth_iban_payment.h
@@ -0,0 +1,39 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/test_auth_iban_payment.h
+ * @brief Anastasis database: test auth iban payment
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_TEST_AUTH_IBAN_PAYMENT_H
+#define ANASTASIS_DATABASE_TEST_AUTH_IBAN_PAYMENT_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Closure for #test_auth_cb.
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_test_auth_iban_payment (
+ const char *debit_account,
+ struct GNUNET_TIME_Timestamp earliest_date,
+ ANASTASIS_DB_AuthIbanTransfercheck cb,
+ void *cb_cls);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/test_challenge_code_satisfied.h b/src/include/anastasis/anastasis-database/test_challenge_code_satisfied.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/test_challenge_code_satisfied.h
+ * @brief Anastasis database: test challenge code satisfied
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_TEST_CHALLENGE_CODE_SATISFIED_H
+#define ANASTASIS_DATABASE_TEST_CHALLENGE_CODE_SATISFIED_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Check if the 'satisfied' bit for the given challenge and code is
+ * 'true' and the challenge code is not yet expired.
+ *
+ * @param truth_uuid identification of the challenge which the code corresponds to
+ * @param code code which is now satisfied
+ * @return transaction status,
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the challenge code is not satisfied or expired
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the challenge code has been marked as satisfied
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_test_challenge_code_satisfied (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const uint64_t code,
+ struct GNUNET_TIME_Timestamp after);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/transaction.h b/src/include/anastasis/anastasis-database/transaction.h
@@ -0,0 +1,60 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/transaction.h
+ * @brief transaction management for the Anastasis database
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_TRANSACTION_H
+#define ANASTASIS_DATABASE_TRANSACTION_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+
+/**
+ * Check that the database connection is still up.
+ */
+void
+ANASTASIS_DB_check_connection (void);
+
+
+/**
+ * Start a transaction.
+ *
+ * @param name unique name identifying the transaction (for debugging),
+ * must point to a constant
+ * @return #GNUNET_OK on success
+ */
+enum GNUNET_GenericReturnValue
+ANASTASIS_DB_start (const char *name);
+
+
+/**
+ * Roll back the current transaction of the database connection.
+ */
+void
+ANASTASIS_DB_rollback (void);
+
+
+/**
+ * Commit the current transaction of the database connection.
+ *
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_commit (void);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/update_challenge_payment.h b/src/include/anastasis/anastasis-database/update_challenge_payment.h
@@ -0,0 +1,41 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/update_challenge_payment.h
+ * @brief Anastasis database: update challenge payment
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_UPDATE_CHALLENGE_PAYMENT_H
+#define ANASTASIS_DATABASE_UPDATE_CHALLENGE_PAYMENT_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Update payment status of challenge
+ *
+ * @param truth_uuid which challenge received a payment
+ * @param payment_identifier proof of payment, must be unique and match pending payment
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_update_challenge_payment (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const struct ANASTASIS_PaymentSecretP *payment_identifier);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/update_lifetime.h b/src/include/anastasis/anastasis-database/update_lifetime.h
@@ -0,0 +1,44 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/update_lifetime.h
+ * @brief Anastasis database: update lifetime
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_UPDATE_LIFETIME_H
+#define ANASTASIS_DATABASE_UPDATE_LIFETIME_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Update account lifetime to the maximum of the current
+ * value and @a eol.
+ *
+ * @param account_pub which account received a payment
+ * @param payment_identifier proof of payment, must be unique and match pending payment
+ * @param eol for how long is the account now paid (absolute)
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_update_lifetime (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ const struct ANASTASIS_PaymentSecretP *payment_identifier,
+ struct GNUNET_TIME_Timestamp eol);
+
+#endif
diff --git a/src/include/anastasis/anastasis-database/verify_challenge_code.h b/src/include/anastasis/anastasis-database/verify_challenge_code.h
@@ -0,0 +1,39 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/anastasis/anastasis-database/verify_challenge_code.h
+ * @brief Anastasis database: verify challenge code
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DATABASE_VERIFY_CHALLENGE_CODE_H
+#define ANASTASIS_DATABASE_VERIFY_CHALLENGE_CODE_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_service.h"
+#include "anastasis/anastasis-database/common.h"
+
+/**
+ * Closure for check_valid_code().
+ */
+enum ANASTASIS_DB_CodeStatus
+ANASTASIS_DB_verify_challenge_code (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const struct GNUNET_HashCode *hashed_code,
+ uint64_t *code,
+ bool *satisfied);
+
+#endif
diff --git a/src/include/anastasis_authorization_lib.h b/src/include/anastasis_authorization_lib.h
@@ -29,14 +29,12 @@
* Load authorization plugin.
*
* @param method name of the method to load
- * @param db database handle to use
* @param AH_cfg configuration to use
* @return plugin handle on success
*/
struct ANASTASIS_AuthorizationPlugin *
ANASTASIS_authorization_plugin_load (
const char *method,
- struct ANASTASIS_DatabasePlugin *db,
const struct GNUNET_CONFIGURATION_Handle *AH_cfg);
diff --git a/src/include/anastasis_authorization_plugin.h b/src/include/anastasis_authorization_plugin.h
@@ -123,11 +123,6 @@ enum ANASTASIS_AUTHORIZATION_SolveResult
struct ANASTASIS_AuthorizationContext
{
/**
- * Database handle.
- */
- struct ANASTASIS_DatabasePlugin *db;
-
- /**
* Configuration to use.
*/
const struct GNUNET_CONFIGURATION_Handle *cfg;
diff --git a/src/include/anastasis_database_lib.h b/src/include/anastasis_database_lib.h
@@ -1,6 +1,6 @@
/*
This file is part of Anastasis
- Copyright (C) 2019 Anastasis SARL
+ Copyright (C) 2019-2022 Anastasis SARL
Anastasis is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@@ -15,7 +15,7 @@
*/
/**
* @file include/anastasis_database_lib.h
- * @brief database plugin loader
+ * @brief Anastasis database library interface
* @author Dominik Meister
* @author Dennis Neufeld
* @author Christian Grothoff
@@ -23,29 +23,60 @@
#ifndef ANASTASIS_DB_LIB_H
#define ANASTASIS_DB_LIB_H
-#include "anastasis_database_plugin.h"
+#include "anastasis_service.h"
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis/anastasis-database/common.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/event.h"
+#include "anastasis/anastasis-database/create_tables.h"
+#include "anastasis/anastasis-database/drop_tables.h"
+#include "anastasis/anastasis-database/gc.h"
+#include "anastasis/anastasis-database/store_recovery_document.h"
+#include "anastasis/anastasis-database/get_recovery_meta_data.h"
+#include "anastasis/anastasis-database/get_recovery_document.h"
+#include "anastasis/anastasis-database/get_latest_recovery_document.h"
+#include "anastasis/anastasis-database/store_truth.h"
+#include "anastasis/anastasis-database/get_escrow_challenge.h"
+#include "anastasis/anastasis-database/get_key_share.h"
+#include "anastasis/anastasis-database/lookup_account.h"
+#include "anastasis/anastasis-database/check_payment_identifier.h"
+#include "anastasis/anastasis-database/check_challenge_payment.h"
+#include "anastasis/anastasis-database/increment_lifetime.h"
+#include "anastasis/anastasis-database/update_lifetime.h"
+#include "anastasis/anastasis-database/record_recdoc_payment.h"
+#include "anastasis/anastasis-database/record_truth_upload_payment.h"
+#include "anastasis/anastasis-database/check_truth_upload_paid.h"
+#include "anastasis/anastasis-database/verify_challenge_code.h"
+#include "anastasis/anastasis-database/mark_challenge_code_satisfied.h"
+#include "anastasis/anastasis-database/test_challenge_code_satisfied.h"
+#include "anastasis/anastasis-database/create_challenge_code.h"
+#include "anastasis/anastasis-database/mark_challenge_sent.h"
+#include "anastasis/anastasis-database/challenge_gc.h"
+#include "anastasis/anastasis-database/record_challenge_payment.h"
+#include "anastasis/anastasis-database/record_challenge_refund.h"
+#include "anastasis/anastasis-database/lookup_challenge_payment.h"
+#include "anastasis/anastasis-database/update_challenge_payment.h"
+#include "anastasis/anastasis-database/record_auth_iban_payment.h"
+#include "anastasis/anastasis-database/test_auth_iban_payment.h"
+#include "anastasis/anastasis-database/get_last_auth_iban_payment_row.h"
+
/**
- * Initialize the plugin.
+ * Initialize the Anastasis database subsystem.
*
* @param cfg configuration to use
- * @param skip_preflight true if we should skip the usual
- * preflight check which assures us that the DB is actually
- * operational; only anastasis-dbinit should use true here.
- * @return NULL on failure
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
*/
-struct ANASTASIS_DatabasePlugin *
-ANASTASIS_DB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg,
- bool skip_preflight);
+enum GNUNET_GenericReturnValue
+ANASTASIS_DB_init (const struct GNUNET_CONFIGURATION_Handle *cfg);
/**
- * Shutdown the plugin.
- *
- * @param plugin plugin to unload
+ * Shutdown the Anastasis database subsystem.
*/
void
-ANASTASIS_DB_plugin_unload (struct ANASTASIS_DatabasePlugin *plugin);
+ANASTASIS_DB_fini (void);
#endif /* ANASTASIS_DB_LIB_H */
diff --git a/src/include/anastasis_database_plugin.h b/src/include/anastasis_database_plugin.h
@@ -1,884 +0,0 @@
-/*
- This file is part of Anastasis
- Copyright (C) 2019-2022 Anastasis SARL
-
- Anastasis is free software; you can redistribute it and/or modify it under the
- 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
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file include/anastasis_database_plugin.h
- * @brief database access for Anastasis
- * @author Christian Grothoff
- */
-#ifndef ANASTASIS_DATABASE_PLUGIN_H
-#define ANASTASIS_DATABASE_PLUGIN_H
-
-#include "anastasis_service.h"
-#include <gnunet/gnunet_db_lib.h>
-
-/**
- * How long is an offer for a challenge payment valid for payment?
- */
-#define ANASTASIS_CHALLENGE_OFFER_LIFETIME GNUNET_TIME_UNIT_HOURS
-
-/**
- * Return values for checking code validity.
- */
-enum ANASTASIS_DB_CodeStatus
-{
- /**
- * Provided authentication code does not match database content.
- */
- ANASTASIS_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH = -3,
-
- /**
- * Encountered hard error talking to DB.
- */
- ANASTASIS_DB_CODE_STATUS_HARD_ERROR = -2,
-
- /**
- * Encountered serialization error talking to DB.
- */
- ANASTASIS_DB_CODE_STATUS_SOFT_ERROR = -1,
-
- /**
- * We have no challenge in the database.
- */
- ANASTASIS_DB_CODE_STATUS_NO_RESULTS = 0,
-
- /**
- * The provided challenge matches what we have in the database.
- */
- ANASTASIS_DB_CODE_STATUS_VALID_CODE_STORED = 1,
-};
-
-
-/**
- * Return values for checking account validity.
- */
-enum ANASTASIS_DB_AccountStatus
-{
- /**
- * Account is unknown, user should pay to establish it.
- */
- ANASTASIS_DB_ACCOUNT_STATUS_PAYMENT_REQUIRED = -3,
-
- /**
- * Encountered hard error talking to DB.
- */
- ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR = -2,
-
- /**
- * Account is valid, but we have no policy stored yet.
- */
- ANASTASIS_DB_ACCOUNT_STATUS_NO_RESULTS = 0,
-
- /**
- * Account is valid, and we have a policy stored.
- */
- ANASTASIS_DB_ACCOUNT_STATUS_VALID_HASH_RETURNED = 1,
-};
-
-
-/**
- * Return values for storing data in database with payment.
- */
-enum ANASTASIS_DB_StoreStatus
-{
- /**
- * The client has stored too many policies, should pay to store more.
- */
- ANASTASIS_DB_STORE_STATUS_STORE_LIMIT_EXCEEDED = -4,
-
- /**
- * The client needs to pay to store policies.
- */
- ANASTASIS_DB_STORE_STATUS_PAYMENT_REQUIRED = -3,
-
- /**
- * Encountered hard error talking to DB.
- */
- ANASTASIS_DB_STORE_STATUS_HARD_ERROR = -2,
-
- /**
- * Despite retrying, we encountered serialization errors.
- */
- ANASTASIS_DB_STORE_STATUS_SOFT_ERROR = -1,
-
- /**
- * Database did not need an update (document exists).
- */
- ANASTASIS_DB_STORE_STATUS_NO_RESULTS = 0,
-
- /**
- * We successfully stored the document.
- */
- ANASTASIS_DB_STORE_STATUS_SUCCESS = 1,
-};
-
-
-/**
- * Function called on all pending payments for an account or challenge.
- *
- * @param cls closure
- * @param timestamp for how long have we been waiting
- * @param payment_secret payment secret / order id in the backend
- * @param amount how much is the order for
- */
-typedef void
-(*ANASTASIS_DB_PaymentPendingIterator)(
- void *cls,
- struct GNUNET_TIME_Timestamp timestamp,
- const struct ANASTASIS_PaymentSecretP *payment_secret,
- const struct TALER_Amount *amount);
-
-
-/**
- * Function called to test if a given wire transfer
- * satisfied the authentication requirement of the
- * IBAN plugin.
- *
- * @param cls closure
- * @param credit amount that was transferred
- * @param wire_subject subject provided in the wire transfer
- * @return true if this wire transfer satisfied the authentication check
- */
-typedef bool
-(*ANASTASIS_DB_AuthIbanTransfercheck)(
- void *cls,
- const struct TALER_Amount *credit,
- const char *wire_subject);
-
-
-/**
- * Function called on matching meta data. Note that if the client did
- * not provide meta data for @a version, the function will be called
- * with @a recovery_meta_data being NULL.
- *
- * @param cls closure
- * @param version the version of the recovery document
- * @param ts timestamp when the document was uploaded
- * @param recovery_meta_data contains meta data about the encrypted recovery document
- * @param recovery_meta_data_size size of @a recovery_meta_data blob
- * @return #GNUNET_OK to continue to iterate, #GNUNET_NO to abort iteration
- */
-typedef enum GNUNET_GenericReturnValue
-(*ANASTASIS_DB_RecoveryMetaCallback)(void *cls,
- uint32_t version,
- struct GNUNET_TIME_Timestamp ts,
- const void *recovery_meta_data,
- size_t recovery_meta_data_size);
-
-
-/**
- * Handle to interact with the database.
- *
- * Functions ending with "_TR" run their OWN transaction scope
- * and MUST NOT be called from within a transaction setup by the
- * caller. Functions ending with "_NT" require the caller to
- * setup a transaction scope. Functions without a suffix are
- * simple, single SQL queries that MAY be used either way.
- */
-struct ANASTASIS_DatabasePlugin
-{
-
- /**
- * Closure for all callbacks.
- */
- void *cls;
-
- /**
- * Name of the library which generated this plugin. Set by the
- * plugin loader.
- */
- char *library_name;
-
- /**
- * Drop anastasis tables. Used for testcases.
- *
- * @param cls closure
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
- enum GNUNET_GenericReturnValue
- (*drop_tables)(void *cls);
-
- /**
- * Connect to the database.
- *
- * @param cls closure
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
- enum GNUNET_GenericReturnValue
- (*connect)(void *cls);
-
- /**
- * Initialize merchant tables
- *
- * @param cls closure
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
- enum GNUNET_GenericReturnValue
- (*create_tables)(void *cls);
-
- /**
- * Function called to perform "garbage collection" on the
- * database, expiring records we no longer require. Deletes
- * all user records that are not paid up (and by cascade deletes
- * the associated recovery documents). Also deletes expired
- * truth and financial records older than @a fin_expire.
- *
- * @param cls closure
- * @param expire_backups backups older than the given time stamp should be garbage collected
- * @param expire_pending_payments payments still pending from since before
- * this value should be garbage collected
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*gc)(void *cls,
- struct GNUNET_TIME_Absolute expire,
- struct GNUNET_TIME_Absolute expire_pending_payments);
-
- /**
- * Do a pre-flight check that we are not in an uncommitted transaction.
- * If we are, try to commit the previous transaction and output a warning.
- * Does not return anything, as we will continue regardless of the outcome.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @return #GNUNET_OK if everything is fine
- * #GNUNET_NO if a transaction was rolled back
- * #GNUNET_SYSERR on hard errors
- */
- enum GNUNET_GenericReturnValue
- (*preflight)(void *cls);
-
- /**
- * Check that the database connection is still up.
- *
- * @param pg connection to check
- */
- void
- (*check_connection) (void *cls);
-
- /**
- * Roll back the current transaction of a database connection.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @return #GNUNET_OK on success
- */
- void
- (*rollback) (void *cls);
-
- /**
- * Start a transaction.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param name unique name identifying the transaction (for debugging),
- * must point to a constant
- * @return #GNUNET_OK on success
- */
- int
- (*start) (void *cls,
- const char *name);
-
- /**
- * Commit the current transaction of a database connection.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @return transaction status code
- */
- enum GNUNET_DB_QueryStatus
- (*commit)(void *cls);
-
-
- /**
- * Register callback to be invoked on events of type @a es.
- *
- * @param cls database context to use
- * @param es specification of the event to listen for
- * @param timeout how long to wait for the event
- * @param cb function to call when the event happens, possibly
- * multiple times (until cancel is invoked)
- * @param cb_cls closure for @a cb
- * @return handle useful to cancel the listener
- */
- struct GNUNET_DB_EventHandler *
- (*event_listen)(void *cls,
- const struct GNUNET_DB_EventHeaderP *es,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_DB_EventCallback cb,
- void *cb_cls);
-
- /**
- * Stop notifications.
- *
- * @param eh handle to unregister.
- */
- void
- (*event_listen_cancel)(struct GNUNET_DB_EventHandler *eh);
-
-
- /**
- * Notify all that listen on @a es of an event.
- *
- * @param cls database context to use
- * @param es specification of the event to generate
- * @param extra additional event data provided
- * @param extra_size number of bytes in @a extra
- */
- void
- (*event_notify)(void *cls,
- const struct GNUNET_DB_EventHeaderP *es,
- const void *extra,
- size_t extra_size);
-
-
- /**
- * Store encrypted recovery document.
- *
- * @param cls closure
- * @param account_pub public key of the user's account
- * @param account_sig signature affirming storage request
- * @param recovery_data_hash hash of @a data
- * @param recovery_data contains encrypted recovery document
- * @param recovery_data_size size of @a recovery_data blob
- * @param recovery_meta_data contains meta data about the encrypted recovery document
- * @param recovery_meta_data_size size of @a recovery_meta_data blob
- * @param payment_secret identifier for the payment, used to later charge on uploads
- * @param[out] version set to the version assigned to the document by the database
- * @return transaction status, 0 if upload could not be finished because @a payment_secret
- * did not have enough upload left; HARD error if @a payment_secret is unknown, ...
- */
- enum ANASTASIS_DB_StoreStatus
- (*store_recovery_document)(
- void *cls,
- const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
- const struct ANASTASIS_AccountSignatureP *account_sig,
- 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);
-
-
- /**
- * 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
- */
- enum GNUNET_DB_QueryStatus
- (*get_recovery_meta_data)(
- void *cls,
- const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
- uint32_t max_version,
- ANASTASIS_DB_RecoveryMetaCallback cb,
- void *cb_cls);
-
-
- /**
- * Fetch recovery document for user according given version.
- *
- * @param cls closure
- * @param account_pub public key of the user's account
- * @param version the version number of the policy the user requests
- * @param[out] account_sig signature
- * @param[out] recovery_data_hash hash of the current recovery data
- * @param[out] data_size size of data blob
- * @param[out] data blob which contains the recovery document
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*get_recovery_document)(
- void *cls,
- const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
- uint32_t version,
- struct ANASTASIS_AccountSignatureP *account_sig,
- struct GNUNET_HashCode *recovery_data_hash,
- size_t *data_size,
- void **data);
-
-
- /**
- * Fetch latest recovery document for user.
- *
- * @param cls closure
- * @param account_pub public key of the user's account
- * @param account_sig signature
- * @param recovery_data_hash hash of the current recovery data
- * @param[out] data_size set to size of @a data blob
- * @param[out] data set to blob which contains the recovery document
- * @param[out] version set to the version number of the policy being returned
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*get_latest_recovery_document)(
- void *cls,
- const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
- struct ANASTASIS_AccountSignatureP *account_sig,
- struct GNUNET_HashCode *recovery_data_hash,
- size_t *data_size,
- void **data,
- uint32_t *version);
-
-
- /**
- * Upload Truth, which contains the Truth and the KeyShare.
- *
- * @param cls closure
- * @param truth_uuid the identifier for the Truth
- * @param key_share_data contains information of an EncryptedKeyShare
- * @param mime_type presumed mime type of data in @a encrypted_truth
- * @param encrypted_truth contains the encrypted Truth which includes the ground truth i.e. H(challenge answer), phonenumber, SMS
- * @param encrypted_truth_size the size of the Truth
- * @param method name of method
- * @param truth_expiration time till the according data will be stored
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*store_truth)(
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- const struct ANASTASIS_CRYPTO_EncryptedKeyShareP *key_share_data,
- const char *mime_type,
- const void *encrypted_truth,
- size_t encrypted_truth_size,
- const char *method,
- struct GNUNET_TIME_Relative truth_expiration);
-
-
- /**
- * Get the encrypted truth to validate the challenge response
- *
- * @param cls closure
- * @param truth_uuid the identifier for the Truth
- * @param[out] truth contains the encrypted truth
- * @param[out] truth_size size of the encrypted truth
- * @param[out] truth_mime mime type of truth
- * @param[out] method type of the challenge
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*get_escrow_challenge)(
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- void **truth,
- size_t *truth_size,
- char **truth_mime,
- char **method);
-
-
- /**
- * Lookup (encrypted) key share by @a truth_uuid.
- *
- * @param cls closure
- * @param truth_uuid the identifier for the Truth
- * @param[out] key_share set to the encrypted Keyshare
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*get_key_share)(
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- struct ANASTASIS_CRYPTO_EncryptedKeyShareP *key_share);
-
-
- /**
- * Check if an account exists, and if so, return the
- * current @a recovery_document_hash.
- *
- * @param cls closure
- * @param account_pub account identifier
- * @param[out] paid_until until when is the account paid up?
- * @param[out] recovery_data_hash set to hash of @a recovery document
- * @param[out] version set to the recovery policy version
- * @return transaction status
- */
- enum ANASTASIS_DB_AccountStatus
- (*lookup_account)(
- void *cls,
- const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
- struct GNUNET_TIME_Timestamp *paid_until,
- struct GNUNET_HashCode *recovery_data_hash,
- uint32_t *version);
-
-
- /**
- * Check payment identifier. Used to check if a payment identifier given by
- * the user is valid (existing and paid).
- *
- * @param cls closure
- * @param payment_secret payment secret which the user must provide with every upload
- * @param[out] paid bool value to show if payment is paid
- * @param[out] valid_counter bool value to show if post_counter is > 0
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*check_payment_identifier)(
- void *cls,
- const struct ANASTASIS_PaymentSecretP *payment_secret,
- bool *paid,
- bool *valid_counter);
-
-
- /**
- * Check payment identifier. Used to check if a payment identifier given by
- * the user is valid (existing and paid).
- *
- * @param cls closure
- * @param payment_secret payment secret which the user must provide with every upload
- * @param truth_uuid unique identifier of the truth the user must satisfy the challenge
- * @param[out] paid bool value to show if payment is paid
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*check_challenge_payment)(
- void *cls,
- const struct ANASTASIS_PaymentSecretP *payment_secret,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- bool *paid);
-
-
- /**
- * Increment account lifetime by @a lifetime.
- *
- * @param cls closure
- * @param account_pub which account received a payment
- * @param payment_identifier proof of payment, must be unique and match pending payment
- * @param lifetime for how long is the account now paid (increment)
- * @param[out] paid_until set to the end of the lifetime after the operation
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*increment_lifetime)(
- void *cls,
- const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
- const struct ANASTASIS_PaymentSecretP *payment_identifier,
- struct GNUNET_TIME_Relative lifetime,
- struct GNUNET_TIME_Timestamp *paid_until);
-
-
- /**
- * Update account lifetime to the maximum of the current
- * value and @a eol.
- *
- * @param cls closure
- * @param account_pub which account received a payment
- * @param payment_identifier proof of payment, must be unique and match pending payment
- * @param eol for how long is the account now paid (absolute)
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*update_lifetime)(
- void *cls,
- const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
- const struct ANASTASIS_PaymentSecretP *payment_identifier,
- struct GNUNET_TIME_Timestamp eol);
-
-
- /**
- * Store payment. Used to begin a payment, not indicative
- * that the payment actually was made. (That is done
- * when we increment the account's lifetime.)
- *
- * @param cls closure
- * @param account_pub anastasis's public key
- * @param post_counter how many uploads does @a amount pay for
- * @param payment_secret payment secret which the user must provide with every upload
- * @param amount how much we asked for
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*record_recdoc_payment)(
- void *cls,
- const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
- uint32_t post_counter,
- const struct ANASTASIS_PaymentSecretP *payment_secret,
- const struct TALER_Amount *amount);
-
-
- /**
- * Record truth upload payment was made.
- *
- * @param cls closure
- * @param uuid the truth's UUID
- * @param amount the amount that was paid
- * @param duration how long is the truth paid for
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*record_truth_upload_payment)(
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid,
- const struct TALER_Amount *amount,
- struct GNUNET_TIME_Relative duration);
-
-
- /**
- * Inquire whether truth upload payment was made.
- *
- * @param cls closure
- * @param uuid the truth's UUID
- * @param[out] paid_until set for how long this truth is paid for
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*check_truth_upload_paid)(
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid,
- struct GNUNET_TIME_Timestamp *paid_until);
-
-
- /**
- * Verify the provided code with the code on the server.
- * If the code matches the function will return with success, if the code
- * does not match, the retry counter will be decreased by one.
- *
- * @param cls closure
- * @param truth_uuid identification of the challenge which the code corresponds to
- * @param hashed_code code which the user provided and wants to verify
- * @param[out] code set to the original numeric code
- * @param[out] satisfied set to true if the challenge is set to satisfied
- * @return transaction status
- */
- enum ANASTASIS_DB_CodeStatus
- (*verify_challenge_code)(
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- const struct GNUNET_HashCode *hashed_code,
- uint64_t *code,
- bool *satisfied);
-
-
- /**
- * Set the 'satisfied' bit for the given challenge and code to
- * 'true'.
- *
- * @param cls closure
- * @param truth_uuid identification of the challenge which the code corresponds to
- * @param code code which is now satisfied
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*mark_challenge_code_satisfied)(
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- uint64_t code);
-
-
- /**
- * Check if the 'satisfied' bit for the given challenge and code is
- * 'true' and the challenge code is not yet expired.
- *
- * @param cls closure
- * @param truth_uuid identification of the challenge which the code corresponds to
- * @param code code which is now satisfied
- * @param after after what time must the challenge have been created
- * @return transaction status,
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the challenge code is not satisfied or expired
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the challenge code has been marked as satisfied
- */
- enum GNUNET_DB_QueryStatus
- (*test_challenge_code_satisfied)(
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- const uint64_t code,
- struct GNUNET_TIME_Timestamp after);
-
-
- /**
- * Insert a new 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.
- *
- * @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 retry_counter amount of retries allowed
- * @param[out] retransmission_date when to next retransmit
- * @param[out] code set to the code which will be checked for later
- * @return transaction status,
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if we are out of valid tries,
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a code is now in the DB
- */
- enum GNUNET_DB_QueryStatus
- (*create_challenge_code)(
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- struct GNUNET_TIME_Relative rotation_period,
- struct GNUNET_TIME_Relative validity_period,
- uint32_t retry_counter,
- struct GNUNET_TIME_Timestamp *retransmission_date,
- uint64_t *code);
-
-
- /**
- * Remember in the database that we successfully sent a challenge.
- *
- * @param cls closure
- * @param truth_uuid the identifier for the challenge
- * @param code the challenge that was sent
- */
- enum GNUNET_DB_QueryStatus
- (*mark_challenge_sent)(
- void *cls,
- const struct ANASTASIS_PaymentSecretP *payment_secret,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- uint64_t code);
-
-
- /**
- * Store payment for challenge.
- *
- * @param cls closure
- * @param truth_key identifier of the challenge to pay
- * @param payment_secret payment secret which the user must provide with every upload
- * @param amount how much we asked for
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*record_challenge_payment)(
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- const struct ANASTASIS_PaymentSecretP *payment_secret,
- const struct TALER_Amount *amount);
-
-
- /**
- * Record refund for challenge.
- *
- * @param cls closure
- * @param truth_uuid identifier of the challenge to refund
- * @param payment_secret payment secret which the user must provide with every upload
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*record_challenge_refund)(
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- const struct ANASTASIS_PaymentSecretP *payment_secret);
-
-
- /**
- * Lookup for a pending payment for a certain challenge
- *
- * @param cls closure
- * @param truth_uuid identification of the challenge
- * @param[out] payment_secret set to the challenge payment secret
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*lookup_challenge_payment)(
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- struct ANASTASIS_PaymentSecretP *payment_secret);
-
-
- /**
- * Update payment status of challenge
- *
- * @param cls closure
- * @param truth_uuid which challenge received a payment
- * @param payment_identifier proof of payment, must be unique and match pending payment
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*update_challenge_payment)(
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- const struct ANASTASIS_PaymentSecretP *payment_identifier);
-
-
- /**
- * Store inbound IBAN payment made for authentication.
- *
- * @param cls closure
- * @param wire_reference unique identifier inside LibEuFin/Nexus
- * @param wire_subject subject of the wire transfer
- * @param amount how much was transferred
- * @param debit_account account that was debited
- * @param credit_account Anastasis operator account credited
- * @param execution_date when was the transfer made
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*record_auth_iban_payment)(
- void *cls,
- uint64_t wire_reference,
- const char *wire_subject,
- const struct TALER_Amount *amount,
- const char *debit_account,
- const char *credit_account,
- struct GNUNET_TIME_Timestamp execution_date);
-
-
- /**
- * Function to check if we are aware of a wire transfer
- * that satisfies the IBAN plugin's authentication check.
- *
- * @param cls closure
- * @param debit_account which debit account to check
- * @param earliest_date earliest date to check
- * @param cb function to call on all entries found
- * @param cb_cls closure for @a cb
- * @return transaction status,
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a cb
- * returned 'true' once
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if no
- * wire transfers existed for which @a cb returned true
- */
- enum GNUNET_DB_QueryStatus
- (*test_auth_iban_payment)(
- void *cls,
- const char *debit_account,
- struct GNUNET_TIME_Timestamp earliest_date,
- ANASTASIS_DB_AuthIbanTransfercheck cb,
- void *cb_cls);
-
-
- /**
- * Function to check the last known IBAN payment.
- *
- * @param cls closure
- * @param credit_account which credit account to check
- * @param[out] last_row set to the last known row
- * @return transaction status,
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a cb
- * returned 'true' once
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if no
- * wire transfers existed for which @a cb returned true
- */
- enum GNUNET_DB_QueryStatus
- (*get_last_auth_iban_payment_row)(
- void *cls,
- const char *credit_account,
- uint64_t *last_row);
-
-
- /**
- * Function called to remove all expired codes from the database.
- *
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*challenge_gc)(void *cls);
-
-
-};
-#endif
diff --git a/src/include/meson.build b/src/include/meson.build
@@ -8,7 +8,6 @@ install_data(
'anastasis_authorization_plugin.h',
'anastasis_crypto_lib.h',
'anastasis_database_lib.h',
- 'anastasis_database_plugin.h',
'anastasis_eufin_lib.h',
'anastasis_error_codes.h',
'anastasis_redux.h',
@@ -18,3 +17,42 @@ install_data(
'anastasis.h',
install_dir: anastasisincludedir,
)
+
+install_data(
+ 'anastasis/anastasis-database/common.h',
+ 'anastasis/anastasis-database/preflight.h',
+ 'anastasis/anastasis-database/transaction.h',
+ 'anastasis/anastasis-database/event.h',
+ 'anastasis/anastasis-database/create_tables.h',
+ 'anastasis/anastasis-database/drop_tables.h',
+ 'anastasis/anastasis-database/gc.h',
+ 'anastasis/anastasis-database/store_recovery_document.h',
+ 'anastasis/anastasis-database/get_recovery_meta_data.h',
+ 'anastasis/anastasis-database/get_recovery_document.h',
+ 'anastasis/anastasis-database/get_latest_recovery_document.h',
+ 'anastasis/anastasis-database/store_truth.h',
+ 'anastasis/anastasis-database/get_escrow_challenge.h',
+ 'anastasis/anastasis-database/get_key_share.h',
+ 'anastasis/anastasis-database/lookup_account.h',
+ 'anastasis/anastasis-database/check_payment_identifier.h',
+ 'anastasis/anastasis-database/check_challenge_payment.h',
+ 'anastasis/anastasis-database/increment_lifetime.h',
+ 'anastasis/anastasis-database/update_lifetime.h',
+ 'anastasis/anastasis-database/record_recdoc_payment.h',
+ 'anastasis/anastasis-database/record_truth_upload_payment.h',
+ 'anastasis/anastasis-database/check_truth_upload_paid.h',
+ 'anastasis/anastasis-database/verify_challenge_code.h',
+ 'anastasis/anastasis-database/mark_challenge_code_satisfied.h',
+ 'anastasis/anastasis-database/test_challenge_code_satisfied.h',
+ 'anastasis/anastasis-database/create_challenge_code.h',
+ 'anastasis/anastasis-database/mark_challenge_sent.h',
+ 'anastasis/anastasis-database/challenge_gc.h',
+ 'anastasis/anastasis-database/record_challenge_payment.h',
+ 'anastasis/anastasis-database/record_challenge_refund.h',
+ 'anastasis/anastasis-database/lookup_challenge_payment.h',
+ 'anastasis/anastasis-database/update_challenge_payment.h',
+ 'anastasis/anastasis-database/record_auth_iban_payment.h',
+ 'anastasis/anastasis-database/test_auth_iban_payment.h',
+ 'anastasis/anastasis-database/get_last_auth_iban_payment_row.h',
+ install_dir: anastasisincludedir / 'anastasis-database',
+)
diff --git a/src/stasis/anastasis-db_challenge_gc.c b/src/stasis/anastasis-db_challenge_gc.c
@@ -0,0 +1,55 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_challenge_gc.c
+ * @brief Anastasis database: challenge gc
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/challenge_gc.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Function called to remove all expired codes from the database.
+ *
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_challenge_gc (void)
+{
+ struct GNUNET_TIME_Timestamp time_now = GNUNET_TIME_timestamp_get ();
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_timestamp (&time_now),
+ GNUNET_PQ_query_param_end
+ };
+
+ GNUNET_break (GNUNET_OK ==
+ ANASTASIS_DB_preflight ());
+ PREPARE ("gc_challengecodes",
+ "DELETE FROM anastasis_challengecode "
+ "WHERE "
+ "expiration_date < $1;");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "gc_challengecodes",
+ params);
+}
+
+
+/* end of anastasis-db_challenge_gc.c */
diff --git a/src/stasis/anastasis-db_check_challenge_payment.c b/src/stasis/anastasis-db_check_challenge_payment.c
@@ -0,0 +1,71 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_check_challenge_payment.c
+ * @brief Anastasis database: check challenge payment
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/check_challenge_payment.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Check payment identifier. Used to check if a payment identifier given by
+ * the user is valid (existing and paid).
+ *
+ * @param payment_secret payment secret which the user must provide with every upload
+ * @param truth_uuid which truth should we check the payment status of
+ * @param[out] paid bool value to show if payment is paid
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_check_challenge_payment (
+ const struct ANASTASIS_PaymentSecretP *payment_secret,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ bool *paid)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (payment_secret),
+ GNUNET_PQ_query_param_auto_from_type (truth_uuid),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_bool ("paid",
+ paid),
+ GNUNET_PQ_result_spec_end
+ };
+
+ PREPARE ("challenge_payment_select",
+ "SELECT"
+ " paid"
+ " FROM anastasis_challenge_payment"
+ " WHERE payment_identifier=$1"
+ " AND truth_uuid=$2"
+ " AND refunded=FALSE"
+ " AND counter>0;");
+ return GNUNET_PQ_eval_prepared_singleton_select (
+ pg->conn,
+ "challenge_payment_select",
+ params,
+ rs);
+}
+
+
+/* end of anastasis-db_check_challenge_payment.c */
diff --git a/src/stasis/anastasis-db_check_payment_identifier.c b/src/stasis/anastasis-db_check_payment_identifier.c
@@ -0,0 +1,71 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_check_payment_identifier.c
+ * @brief Anastasis database: check payment identifier
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/check_payment_identifier.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Check payment identifier. Used to check if a payment identifier given by
+ * the user is valid (existing and paid).
+ *
+ * @param payment_secret payment secret which the user must provide with every upload
+ * @param[out] paid bool value to show if payment is paid
+ * @param[out] valid_counter bool value to show if post_counter is > 0
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_check_payment_identifier (
+ const struct ANASTASIS_PaymentSecretP *payment_secret,
+ bool *paid,
+ bool *valid_counter)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (payment_secret),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_bool ("paid",
+ paid),
+ GNUNET_PQ_result_spec_bool ("valid_counter",
+ valid_counter),
+ GNUNET_PQ_result_spec_end
+ };
+
+ PREPARE ("recdoc_payment_select",
+ "SELECT"
+ " creation_date"
+ ",post_counter > 0 AS valid_counter"
+ ",amount"
+ ",paid"
+ " FROM anastasis_recdoc_payment"
+ " WHERE payment_identifier=$1;");
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "recdoc_payment_select",
+ params,
+ rs);
+}
+
+
+/* end of anastasis-db_check_payment_identifier.c */
diff --git a/src/stasis/anastasis-db_check_truth_upload_paid.c b/src/stasis/anastasis-db_check_truth_upload_paid.c
@@ -0,0 +1,66 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_check_truth_upload_paid.c
+ * @brief Anastasis database: check truth upload paid
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/check_truth_upload_paid.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Inquire whether truth upload payment was made.
+ *
+ * @param uuid the truth's UUID
+ * @param[out] paid_until set for how long this truth is paid for
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_check_truth_upload_paid (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid,
+ struct GNUNET_TIME_Timestamp *paid_until)
+{
+ 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_timestamp (&now),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_timestamp ("expiration",
+ paid_until),
+ GNUNET_PQ_result_spec_end
+ };
+
+ PREPARE ("truth_payment_select",
+ "SELECT"
+ " expiration"
+ " FROM anastasis_truth_payment"
+ " WHERE truth_uuid=$1"
+ " AND expiration>$2;");
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "truth_payment_select",
+ params,
+ rs);
+}
+
+
+/* end of anastasis-db_check_truth_upload_paid.c */
diff --git a/src/stasis/anastasis-db_create_challenge_code.c b/src/stasis/anastasis-db_create_challenge_code.c
@@ -0,0 +1,196 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_create_challenge_code.c
+ * @brief Anastasis database: create challenge code
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/create_challenge_code.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Create a new 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.
+ *
+ * @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 retry_counter amount of retries allowed
+ * @param[out] retransmission_date when to next retransmit
+ * @param[out] code set to the code which will be checked for later
+ * @return transaction status,
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if we are out of valid tries,
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a code is now in the DB
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_create_challenge_code (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ struct GNUNET_TIME_Relative rotation_period,
+ struct GNUNET_TIME_Relative validity_period,
+ uint32_t retry_counter,
+ struct GNUNET_TIME_Timestamp *retransmission_date,
+ uint64_t *code)
+{
+ struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
+ struct GNUNET_TIME_Timestamp expiration_date;
+ struct GNUNET_TIME_Absolute ex_rot;
+
+ PREPARE ("challengecode_select_meta",
+ "SELECT "
+ " code"
+ ",retry_counter"
+ ",retransmission_date"
+ " FROM anastasis_challengecode"
+ " WHERE truth_uuid=$1"
+ " AND expiration_date > $2"
+ " AND creation_date > $3"
+ " ORDER BY creation_date DESC"
+ " LIMIT 1;");
+ PREPARE ("challengecode_insert",
+ "INSERT INTO anastasis_challengecode "
+ "(truth_uuid"
+ ",code"
+ ",creation_date"
+ ",expiration_date"
+ ",retry_counter"
+ ") VALUES "
+ "($1, $2, $3, $4, $5);");
+ 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++)
+ {
+ if (GNUNET_OK !=
+ ANASTASIS_DB_start (
+ "create_challenge_code"))
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+
+ {
+ uint32_t old_retry_counter;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (truth_uuid),
+ GNUNET_PQ_query_param_timestamp (&now),
+ GNUNET_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_uint32 ("retry_counter",
+ &old_retry_counter),
+ GNUNET_PQ_result_spec_timestamp ("retransmission_date",
+ retransmission_date),
+ 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);
+ ANASTASIS_DB_rollback ();
+ return qs;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "No active challenge found, creating a fresh one\n");
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ if (0 == old_retry_counter)
+ {
+ ANASTASIS_DB_rollback ();
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Active challenge %llu has zero tries left, refusing to create another one\n",
+ (unsigned long long) *code);
+ return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+ }
+ ANASTASIS_DB_rollback ();
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "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,
+ 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),
+ 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
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "challengecode_insert",
+ params);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ ANASTASIS_DB_rollback ();
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break (0);
+ ANASTASIS_DB_rollback ();
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Created fresh challenge with %u tries left\n",
+ (unsigned int) retry_counter);
+ break;
+ }
+ }
+
+ {
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = ANASTASIS_DB_commit ();
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto retry;
+ if (qs < 0)
+ return qs;
+ }
+ return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+retry:
+ ANASTASIS_DB_rollback ();
+ }
+ return GNUNET_DB_STATUS_SOFT_ERROR;
+}
+
+
+/* end of anastasis-db_create_challenge_code.c */
diff --git a/src/stasis/anastasis-db_create_tables.c b/src/stasis/anastasis-db_create_tables.c
@@ -0,0 +1,55 @@
+/*
+ This file is part of Anastasis
+ 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 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_create_tables.c
+ * @brief create the Anastasis database tables
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/create_tables.h"
+
+
+enum GNUNET_GenericReturnValue
+ANASTASIS_DB_create_tables (void)
+{
+ if (GNUNET_SYSERR ==
+ GNUNET_PQ_load_versioning (pg->conn))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_PQ_run_sql (pg->conn,
+ "stasis-"))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+#if 0
+ if (GNUNET_OK !=
+ GNUNET_PQ_exec_sql (pg->conn,
+ "procedures"))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+#endif
+ return GNUNET_OK;
+}
+
+
+/* end of anastasis-db_create_tables.c */
diff --git a/src/stasis/anastasis-db_drop_tables.c b/src/stasis/anastasis-db_drop_tables.c
@@ -0,0 +1,34 @@
+/*
+ This file is part of Anastasis
+ 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 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_drop_tables.c
+ * @brief drop the Anastasis database tables
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/drop_tables.h"
+
+
+enum GNUNET_GenericReturnValue
+ANASTASIS_DB_drop_tables (void)
+{
+ return GNUNET_PQ_exec_sql (pg->conn,
+ "drop");
+}
+
+
+/* end of anastasis-db_drop_tables.c */
diff --git a/src/stasis/anastasis-db_gc.c b/src/stasis/anastasis-db_gc.c
@@ -0,0 +1,76 @@
+/*
+ This file is part of Anastasis
+ 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 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_gc.c
+ * @brief garbage collection for the Anastasis database
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/gc.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include "anastasis/anastasis-database/transaction.h"
+
+
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_gc (struct GNUNET_TIME_Absolute expire_backups,
+ struct GNUNET_TIME_Absolute expire_pending_payments)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_absolute_time (&expire_backups),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_QueryParam params2[] = {
+ GNUNET_PQ_query_param_absolute_time (&expire_pending_payments),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ GNUNET_break (GNUNET_OK ==
+ ANASTASIS_DB_preflight ());
+#if 0
+ /* FIXME: should we do this? */
+ PREPARE ("gc_challenge_pending_payments",
+ "DELETE FROM anastasis_challenge_payment "
+ "WHERE"
+ " (paid=FALSE"
+ " OR"
+ " refunded)"
+ " AND"
+ " creation_date < $1;"),
+#endif
+ PREPARE ("gc_accounts",
+ "DELETE FROM anastasis_user "
+ "WHERE"
+ " expiration_date < $1;");
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "gc_accounts",
+ params);
+ if (qs < 0)
+ return qs;
+ PREPARE ("gc_recdoc_pending_payments",
+ "DELETE FROM anastasis_recdoc_payment "
+ "WHERE"
+ " paid=FALSE"
+ " AND"
+ " creation_date < $1;");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "gc_recdoc_pending_payments",
+ params2);
+}
+
+
+/* end of anastasis-db_gc.c */
diff --git a/src/stasis/anastasis-db_get_escrow_challenge.c b/src/stasis/anastasis-db_get_escrow_challenge.c
@@ -0,0 +1,76 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_get_escrow_challenge.c
+ * @brief Anastasis database: get escrow challenge
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/get_escrow_challenge.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Get the encrypted truth to validate the challenge response
+ *
+ * @param truth_uuid the identifier for the Truth
+ * @param[out] truth contains the encrypted truth
+ * @param[out] truth_size size of the encrypted truth
+ * @param[out] truth_mime mime type of truth
+ * @param[out] method type of the challenge
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_get_escrow_challenge (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ void **truth,
+ size_t *truth_size,
+ char **truth_mime,
+ char **method)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (truth_uuid),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_variable_size ("encrypted_truth",
+ truth,
+ truth_size),
+ GNUNET_PQ_result_spec_string ("truth_mime",
+ truth_mime),
+ GNUNET_PQ_result_spec_string ("method_name",
+ method),
+ GNUNET_PQ_result_spec_end
+ };
+
+ PREPARE ("truth_select",
+ "SELECT "
+ " method_name"
+ ",encrypted_truth"
+ ",truth_mime"
+ " FROM anastasis_truth"
+ " WHERE truth_uuid=$1;");
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "truth_select",
+ params,
+ rs);
+}
+
+
+/* end of anastasis-db_get_escrow_challenge.c */
diff --git a/src/stasis/anastasis-db_get_key_share.c b/src/stasis/anastasis-db_get_key_share.c
@@ -0,0 +1,64 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_get_key_share.c
+ * @brief Anastasis database: get key share
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/get_key_share.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Lookup (encrypted) key share by @a truth_uuid.
+ *
+ * @param truth_uuid the identifier for the Truth
+ * @param[out] key_share contains the encrypted Keyshare
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_get_key_share (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ struct ANASTASIS_CRYPTO_EncryptedKeyShareP *key_share)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (truth_uuid),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("key_share_data",
+ key_share),
+ GNUNET_PQ_result_spec_end
+ };
+
+ PREPARE ("key_share_select",
+ "SELECT "
+ "key_share_data "
+ "FROM "
+ "anastasis_truth "
+ "WHERE truth_uuid =$1;");
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "key_share_select",
+ params,
+ rs);
+}
+
+
+/* end of anastasis-db_get_key_share.c */
diff --git a/src/stasis/anastasis-db_get_last_auth_iban_payment_row.c b/src/stasis/anastasis-db_get_last_auth_iban_payment_row.c
@@ -0,0 +1,69 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_get_last_auth_iban_payment_row.c
+ * @brief Anastasis database: get last auth iban payment row
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/get_last_auth_iban_payment_row.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Function to check the last known IBAN payment.
+ *
+ * @param credit_account which credit account to check
+ * @param[out] last_row set to the last known row
+ * @return transaction status,
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a cb
+ * returned 'true' once
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if no
+ * wire transfers existed for which @a cb returned true
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_get_last_auth_iban_payment_row (
+ const char *credit_account,
+ uint64_t *last_row)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (credit_account),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("wire_reference",
+ last_row),
+ GNUNET_PQ_result_spec_end
+ };
+
+ 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;");
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "get_last_auth_iban_payment",
+ params,
+ rs);
+}
+
+
+/* end of anastasis-db_get_last_auth_iban_payment_row.c */
diff --git a/src/stasis/anastasis-db_get_latest_recovery_document.c b/src/stasis/anastasis-db_get_latest_recovery_document.c
@@ -0,0 +1,85 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_get_latest_recovery_document.c
+ * @brief Anastasis database: get latest recovery document
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/get_latest_recovery_document.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Fetch latest recovery document for user.
+ *
+ * @param account_pub public key of the user's account
+ * @param account_sig signature
+ * @param recovery_data_hash hash of the current recovery data
+ * @param data_size size of data blob
+ * @param data blob which contains the recovery document
+ * @param[out] version set to the version number of the policy being returned
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_get_latest_recovery_document (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ struct ANASTASIS_AccountSignatureP *account_sig,
+ struct GNUNET_HashCode *recovery_data_hash,
+ size_t *data_size,
+ void **data,
+ uint32_t *version)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint32 ("version",
+ version),
+ GNUNET_PQ_result_spec_auto_from_type ("account_sig",
+ account_sig),
+ GNUNET_PQ_result_spec_auto_from_type ("recovery_data_hash",
+ recovery_data_hash),
+ GNUNET_PQ_result_spec_variable_size ("recovery_data",
+ data,
+ data_size),
+ GNUNET_PQ_result_spec_end
+ };
+
+ GNUNET_break (GNUNET_OK ==
+ ANASTASIS_DB_preflight ());
+ PREPARE ("latest_recoverydocument_select",
+ "SELECT "
+ " version"
+ ",account_sig"
+ ",recovery_data_hash"
+ ",recovery_data"
+ " FROM anastasis_recoverydocument"
+ " WHERE user_id=$1"
+ " ORDER BY version DESC"
+ " LIMIT 1;");
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "latest_recoverydocument_select",
+ params,
+ rs);
+}
+
+
+/* end of anastasis-db_get_latest_recovery_document.c */
diff --git a/src/stasis/anastasis-db_get_recovery_document.c b/src/stasis/anastasis-db_get_recovery_document.c
@@ -0,0 +1,80 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_get_recovery_document.c
+ * @brief Anastasis database: get recovery document
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/get_recovery_document.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Fetch recovery document for user according given version.
+ *
+ * @param account_pub public key of the user's account
+ * @param version the version number of the policy the user requests
+ * @param[out] account_sig signature
+ * @param[out] recovery_data_hash hash of the current recovery data
+ * @param[out] data_size size of data blob
+ * @param[out] data blob which contains the recovery document
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_get_recovery_document (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ uint32_t version,
+ struct ANASTASIS_AccountSignatureP *account_sig,
+ struct GNUNET_HashCode *recovery_data_hash,
+ size_t *data_size,
+ void **data)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_uint32 (&version),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("account_sig",
+ account_sig),
+ GNUNET_PQ_result_spec_auto_from_type ("recovery_data_hash",
+ recovery_data_hash),
+ GNUNET_PQ_result_spec_variable_size ("recovery_data",
+ data,
+ data_size),
+ GNUNET_PQ_result_spec_end
+ };
+
+ PREPARE ("recoverydocument_select",
+ "SELECT "
+ " account_sig"
+ ",recovery_data_hash"
+ ",recovery_data"
+ " FROM anastasis_recoverydocument"
+ " WHERE user_id=$1"
+ " AND version=$2;");
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "recoverydocument_select",
+ params,
+ rs);
+}
+
+
+/* end of anastasis-db_get_recovery_document.c */
diff --git a/src/stasis/anastasis-db_get_recovery_meta_data.c b/src/stasis/anastasis-db_get_recovery_meta_data.c
@@ -0,0 +1,156 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_get_recovery_meta_data.c
+ * @brief Anastasis database: get recovery meta data
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/get_recovery_meta_data.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+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
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_get_recovery_meta_data (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ uint32_t max_version,
+ ANASTASIS_DB_RecoveryMetaCallback cb,
+ void *cb_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;
+
+ 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;");
+ 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;
+}
+
+
+/* end of anastasis-db_get_recovery_meta_data.c */
diff --git a/src/stasis/anastasis-db_increment_lifetime.c b/src/stasis/anastasis-db_increment_lifetime.c
@@ -0,0 +1,245 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_increment_lifetime.c
+ * @brief Anastasis database: increment lifetime
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/increment_lifetime.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Increment account lifetime based on payment having been received.
+ * Does nothing if the payment is not new.
+ *
+ * @param account_pub which account received a payment
+ * @param payment_identifier proof of payment, must be unique and match pending payment
+ * @param lifetime for how long is the account now paid (increment)
+ * @param[out] paid_until set to the end of the lifetime after the operation
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_increment_lifetime (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ const struct ANASTASIS_PaymentSecretP *payment_identifier,
+ struct GNUNET_TIME_Relative lifetime,
+ struct GNUNET_TIME_Timestamp *paid_until)
+{
+ 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));
+ PREPARE ("user_insert",
+ "INSERT INTO anastasis_user "
+ "(user_id"
+ ",expiration_date"
+ ") VALUES "
+ "($1, $2);");
+ PREPARE ("user_select",
+ "SELECT"
+ " expiration_date "
+ "FROM anastasis_user"
+ " WHERE user_id=$1"
+ " FOR UPDATE;");
+ PREPARE ("user_update",
+ "UPDATE anastasis_user"
+ " SET "
+ " expiration_date=$1"
+ " WHERE user_id=$2;");
+ PREPARE ("recdoc_payment_done",
+ "UPDATE anastasis_recdoc_payment "
+ "SET"
+ " paid=TRUE "
+ "WHERE"
+ " payment_identifier=$1"
+ " AND"
+ " user_id=$2"
+ " AND"
+ " paid=FALSE;");
+ for (unsigned int retries = 0; retries<MAX_RETRIES; retries++)
+ {
+ if (GNUNET_OK !=
+ ANASTASIS_DB_start (
+ "increment lifetime"))
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (payment_identifier),
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_end
+ };
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "recdoc_payment_done",
+ params);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ ANASTASIS_DB_rollback ();
+ *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;
+ }
+ }
+
+ {
+ enum GNUNET_DB_QueryStatus qs2;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_TIME_Timestamp expiration;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_timestamp ("expiration_date",
+ &expiration),
+ GNUNET_PQ_result_spec_end
+ };
+
+ qs2 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "user_select",
+ params,
+ rs);
+ switch (qs2)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ ANASTASIS_DB_rollback ();
+ return qs2;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ {
+ /* inconsistent, cannot have recdoc payment but no user!? */
+ GNUNET_break (0);
+ ANASTASIS_DB_rollback ();
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ else
+ {
+ /* user does not exist, create new one */
+ struct GNUNET_PQ_QueryParam iparams[] = {
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_timestamp (&expiration),
+ GNUNET_PQ_query_param_end
+ };
+
+ 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",
+ iparams);
+ }
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ {
+ /* existing rec doc payment (payment replay), return
+ existing expiration */
+ *paid_until = expiration;
+ ANASTASIS_DB_rollback ();
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Payment existed, lifetime of account %s unchanged at %s\n",
+ TALER_B2S (account_pub),
+ GNUNET_TIME_timestamp2s (*paid_until));
+ return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+ }
+ else
+ {
+ /* user exists, payment is new, update expiration_date */
+ struct GNUNET_PQ_QueryParam iparams[] = {
+ GNUNET_PQ_query_param_timestamp (&expiration),
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_end
+ };
+
+ 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",
+ iparams);
+ }
+ break;
+ }
+ }
+
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ ANASTASIS_DB_rollback ();
+ return qs;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break (0);
+ ANASTASIS_DB_rollback ();
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+ qs = ANASTASIS_DB_commit ();
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto retry;
+ if (qs < 0)
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Incremented lifetime of account %s to %s\n",
+ TALER_B2S (account_pub),
+ GNUNET_TIME_timestamp2s (*paid_until));
+ return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+retry:
+ ANASTASIS_DB_rollback ();
+ }
+ return GNUNET_DB_STATUS_SOFT_ERROR;
+}
+
+
+/* end of anastasis-db_increment_lifetime.c */
diff --git a/src/stasis/anastasis-db_lookup_account.c b/src/stasis/anastasis-db_lookup_account.c
@@ -0,0 +1,136 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_lookup_account.c
+ * @brief Anastasis database: lookup account
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/lookup_account.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Check if an account exists, and if so, return the
+ * current @a recovery_document_hash.
+ *
+ * @param account_pub account identifier
+ * @param[out] paid_until until when is the account paid up?
+ * @param[out] recovery_data_hash set to hash of @a recovery document
+ * @param[out] version set to the recovery policy version
+ * @return transaction status
+ */
+enum ANASTASIS_DB_AccountStatus
+ANASTASIS_DB_lookup_account (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ struct GNUNET_TIME_Timestamp *paid_until,
+ struct GNUNET_HashCode *recovery_data_hash,
+ uint32_t *version)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ PREPARE ("user_select2",
+ "SELECT"
+ " expiration_date "
+ "FROM anastasis_user"
+ " WHERE user_id=$1"
+ " FOR UPDATE;");
+ PREPARE ("latest_recovery_version_select",
+ "SELECT"
+ " version"
+ ",recovery_data_hash"
+ ",expiration_date"
+ " FROM anastasis_recoverydocument"
+ " JOIN anastasis_user USING (user_id)"
+ " WHERE user_id=$1"
+ " ORDER BY version DESC"
+ " LIMIT 1;");
+ GNUNET_break (GNUNET_OK ==
+ ANASTASIS_DB_preflight ());
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ 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",
+ version),
+ GNUNET_PQ_result_spec_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "latest_recovery_version_select",
+ params,
+ rs);
+ }
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ return ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ return ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ break; /* handle interesting case below */
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ return ANASTASIS_DB_ACCOUNT_STATUS_VALID_HASH_RETURNED;
+ }
+
+ /* check if account exists */
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_timestamp ("expiration_date",
+ paid_until),
+ GNUNET_PQ_result_spec_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "user_select2",
+ params,
+ rs);
+ }
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ return ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ return ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ /* indicates: no account */
+ return ANASTASIS_DB_ACCOUNT_STATUS_PAYMENT_REQUIRED;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ /* indicates: no backup */
+ *version = UINT32_MAX;
+ memset (recovery_data_hash,
+ 0,
+ sizeof (*recovery_data_hash));
+ return ANASTASIS_DB_ACCOUNT_STATUS_NO_RESULTS;
+ default:
+ GNUNET_break (0);
+ return ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR;
+ }
+}
+
+
+/* end of anastasis-db_lookup_account.c */
diff --git a/src/stasis/anastasis-db_lookup_challenge_payment.c b/src/stasis/anastasis-db_lookup_challenge_payment.c
@@ -0,0 +1,78 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_lookup_challenge_payment.c
+ * @brief Anastasis database: lookup challenge payment
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/lookup_challenge_payment.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Lookup pending payment for a certain challenge.
+ *
+ * @param truth_uuid identification of the challenge
+ * @param[out] payment_secret set to the challenge payment secret
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_lookup_challenge_payment (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ struct ANASTASIS_PaymentSecretP *payment_secret)
+{
+ struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+ 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_timestamp (&recent),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("payment_identifier",
+ payment_secret),
+ GNUNET_PQ_result_spec_end
+ };
+
+ PREPARE ("challenge_pending_payment_select",
+ "SELECT"
+ " creation_date"
+ ",payment_identifier"
+ ",amount"
+ " FROM anastasis_challenge_payment"
+ " WHERE"
+ " paid=FALSE"
+ " AND"
+ " refunded=FALSE"
+ " AND"
+ " truth_uuid=$1"
+ " AND"
+ " creation_date > $2;");
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "challenge_pending_payment_select",
+ params,
+ rs);
+}
+
+
+/* end of anastasis-db_lookup_challenge_payment.c */
diff --git a/src/stasis/anastasis-db_mark_challenge_code_satisfied.c b/src/stasis/anastasis-db_mark_challenge_code_satisfied.c
@@ -0,0 +1,66 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_mark_challenge_code_satisfied.c
+ * @brief Anastasis database: mark challenge code satisfied
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/mark_challenge_code_satisfied.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Set the 'satisfied' bit for the given challenge and code to
+ * 'true'.
+ *
+ * @param truth_uuid identification of the challenge which the code corresponds to
+ * @param code code which is now satisfied
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_mark_challenge_code_satisfied (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const uint64_t code)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (truth_uuid),
+ GNUNET_PQ_query_param_uint64 (&code),
+ GNUNET_PQ_query_param_end
+ };
+
+ PREPARE ("challengecode_set_satisfied",
+ "UPDATE anastasis_challengecode"
+ " SET satisfied=TRUE"
+ " WHERE truth_uuid=$1"
+ " AND code=$2"
+ " AND creation_date IN"
+ " (SELECT creation_date"
+ " FROM anastasis_challengecode"
+ " WHERE truth_uuid=$1"
+ " AND code=$2"
+ " ORDER BY creation_date DESC"
+ " LIMIT 1);");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "challengecode_set_satisfied",
+ params);
+}
+
+
+/* end of anastasis-db_mark_challenge_code_satisfied.c */
diff --git a/src/stasis/anastasis-db_mark_challenge_sent.c b/src/stasis/anastasis-db_mark_challenge_sent.c
@@ -0,0 +1,98 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_mark_challenge_sent.c
+ * @brief Anastasis database: mark challenge sent
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/mark_challenge_sent.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Remember in the database that we successfully sent a challenge.
+ *
+ * @param payment_secret payment secret which the user must provide with every upload
+ * @param truth_uuid the identifier for the challenge
+ * @param code the challenge that was sent
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_mark_challenge_sent (
+ const struct ANASTASIS_PaymentSecretP *payment_secret,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ uint64_t code)
+{
+ enum GNUNET_DB_QueryStatus qs;
+
+ PREPARE ("challengecode_mark_sent",
+ "UPDATE anastasis_challengecode"
+ " SET retransmission_date=$3"
+ " WHERE truth_uuid=$1"
+ " AND code=$2"
+ " AND creation_date IN"
+ " (SELECT creation_date"
+ " FROM anastasis_challengecode"
+ " WHERE truth_uuid=$1"
+ " AND code=$2"
+ " ORDER BY creation_date DESC"
+ " LIMIT 1);");
+ PREPARE ("challengepayment_dec_counter",
+ "UPDATE anastasis_challenge_payment"
+ " SET counter=counter - 1"
+ " WHERE truth_uuid=$1"
+ " AND payment_identifier=$2"
+ " AND counter > 0;");
+ {
+ 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),
+ GNUNET_PQ_query_param_timestamp (&now),
+ GNUNET_PQ_query_param_end
+ };
+
+ 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),
+ GNUNET_PQ_query_param_auto_from_type (payment_secret),
+ GNUNET_PQ_query_param_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "challengepayment_dec_counter",
+ params);
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; /* probably was free */
+ return qs;
+ }
+}
+
+
+/* end of anastasis-db_mark_challenge_sent.c */
diff --git a/src/stasis/anastasis-db_pg.c b/src/stasis/anastasis-db_pg.c
@@ -0,0 +1,220 @@
+/*
+ This file is part of Anastasis
+ 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 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_pg.c
+ * @brief shared database state and helpers for the Anastasis postgres backend
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/event.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Global database state.
+ */
+struct PostgresClosure *pg;
+
+
+enum GNUNET_GenericReturnValue
+ANASTASIS_DB_start (const char *name)
+{
+ struct GNUNET_PQ_ExecuteStatement es[] = {
+ GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"),
+ GNUNET_PQ_EXECUTE_STATEMENT_END
+ };
+
+ GNUNET_break (GNUNET_OK ==
+ ANASTASIS_DB_preflight ());
+ pg->transaction_name = name;
+ if (GNUNET_OK !=
+ GNUNET_PQ_exec_statements (pg->conn,
+ es))
+ {
+ TALER_LOG_ERROR ("Failed to start transaction\n");
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+void
+ANASTASIS_DB_rollback (void)
+{
+ struct GNUNET_PQ_ExecuteStatement es[] = {
+ GNUNET_PQ_make_execute ("ROLLBACK"),
+ GNUNET_PQ_EXECUTE_STATEMENT_END
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_exec_statements (pg->conn,
+ es))
+ {
+ TALER_LOG_ERROR ("Failed to rollback transaction\n");
+ GNUNET_break (0);
+ }
+ pg->transaction_name = NULL;
+}
+
+
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_commit (void)
+{
+ enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_PQ_QueryParam no_params[] = {
+ GNUNET_PQ_query_param_end
+ };
+
+ PREPARE ("do_commit",
+ "COMMIT");
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "do_commit",
+ no_params);
+ pg->transaction_name = NULL;
+ return qs;
+}
+
+
+struct GNUNET_DB_EventHandler *
+ANASTASIS_DB_event_listen (const struct GNUNET_DB_EventHeaderP *es,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_DB_EventCallback cb,
+ void *cb_cls)
+{
+ return GNUNET_PQ_event_listen (pg->conn,
+ es,
+ timeout,
+ cb,
+ cb_cls);
+}
+
+
+void
+ANASTASIS_DB_event_listen_cancel (struct GNUNET_DB_EventHandler *eh)
+{
+ GNUNET_PQ_event_listen_cancel (eh);
+}
+
+
+void
+ANASTASIS_DB_event_notify (const struct GNUNET_DB_EventHeaderP *es,
+ const void *extra,
+ size_t extra_size)
+{
+ GNUNET_PQ_event_notify (pg->conn,
+ es,
+ extra,
+ extra_size);
+}
+
+
+/**
+ * Function called each time we connect or reconnect to the
+ * database. Gives the application a chance to run some
+ * per-connection initialization logic.
+ *
+ * @param cls unused, NULL
+ * @param pq database connection handle
+ */
+static void
+reconnect_cb (void *cls,
+ struct GNUNET_PQ_Context *pq)
+{
+#if AUTO_EXPLAIN
+ /* Enable verbose logging to see where queries do not
+ properly use indices */
+ struct GNUNET_PQ_ExecuteStatement es[] = {
+ GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"),
+ GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"),
+ GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"),
+ GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"),
+ /* https://wiki.postgresql.org/wiki/Serializable suggests to really
+ force the default to 'serializable' if SSI is to be used. */
+ GNUNET_PQ_make_try_execute (
+ "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[] = {
+ GNUNET_PQ_make_execute ("SET search_path TO anastasis;"),
+ GNUNET_PQ_EXECUTE_STATEMENT_END
+ };
+#endif
+
+ (void) cls;
+ if (GNUNET_OK !=
+ GNUNET_PQ_exec_statements (pq,
+ es))
+ {
+ GNUNET_break (0);
+ return;
+ }
+ pg->prep_gen++;
+}
+
+
+enum GNUNET_GenericReturnValue
+ANASTASIS_DB_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ pg = GNUNET_new (struct PostgresClosure);
+ pg->cfg = cfg;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "anastasis",
+ "CURRENCY",
+ &pg->currency))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "anastasis",
+ "CURRENCY");
+ GNUNET_free (pg);
+ return GNUNET_SYSERR;
+ }
+ pg->conn = GNUNET_PQ_init (pg->cfg,
+ "stasis-postgres",
+ &reconnect_cb,
+ pg);
+ if (NULL == pg->conn)
+ {
+ GNUNET_break (0);
+ ANASTASIS_DB_fini ();
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+void
+ANASTASIS_DB_fini (void)
+{
+ if (NULL == pg)
+ return;
+ if (NULL != pg->conn)
+ GNUNET_PQ_disconnect (pg->conn);
+ GNUNET_free (pg->currency);
+ GNUNET_free (pg);
+}
+
+
+/* end of anastasis-db_pg.c */
diff --git a/src/stasis/anastasis-db_pg.h b/src/stasis/anastasis-db_pg.h
@@ -0,0 +1,115 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_pg.h
+ * @brief internal shared state for the Anastasis postgres database
+ * @author Christian Grothoff
+ */
+#ifndef ANASTASIS_DB_PG_H
+#define ANASTASIS_DB_PG_H
+
+#include "platform.h"
+#include "anastasis_util_lib.h"
+#include "anastasis_database_lib.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include <gnunet/gnunet_pq_lib.h>
+#include <taler/taler_pq_lib.h>
+
+/**
+ * How long do we keep transient accounts open (those that have
+ * not been paid at all, but are awaiting payment). This puts
+ * a cap on how long users have to make a payment after a payment
+ * request was generated.
+ */
+#define TRANSIENT_LIFETIME GNUNET_TIME_UNIT_WEEKS
+
+/**
+ * How often do we re-try if we run into a DB serialization error?
+ */
+#define MAX_RETRIES 3
+
+
+/**
+ * Shared database state for the Anastasis postgres backend.
+ */
+struct PostgresClosure
+{
+
+ /**
+ * Postgres connection handle.
+ */
+ struct GNUNET_PQ_Context *conn;
+
+ /**
+ * Underlying configuration.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Name of the currently active transaction, NULL if none is active.
+ */
+ const char *transaction_name;
+
+ /**
+ * Currency we accept payments in.
+ */
+ char *currency;
+
+ /**
+ * Prepared statements have been initialized in this edition.
+ */
+ uint64_t prep_gen;
+};
+
+
+/**
+ * Global database state, initialized by ANASTASIS_DB_init().
+ */
+extern struct PostgresClosure *pg;
+
+/**
+ * Prepares SQL statement @a sql under @a name for
+ * connection @a pg once.
+ * Returns with #GNUNET_DB_STATUS_HARD_ERROR on failure.
+ *
+ * @param name name to prepare the statement under
+ * @param sql actual SQL text
+ */
+#define PREPARE(name,sql) \
+ do { \
+ static unsigned long long gen; \
+ \
+ if (gen < pg->prep_gen) \
+ { \
+ struct GNUNET_PQ_PreparedStatement ps[] = { \
+ GNUNET_PQ_make_prepare (name, sql), \
+ GNUNET_PQ_PREPARED_STATEMENT_END \
+ }; \
+ \
+ if (GNUNET_OK != \
+ GNUNET_PQ_prepare_statements (pg->conn, \
+ ps)) \
+ { \
+ GNUNET_break (0); \
+ return GNUNET_DB_STATUS_HARD_ERROR; \
+ } \
+ gen = pg->prep_gen; \
+ } \
+ } while (0)
+
+
+#endif
diff --git a/src/stasis/anastasis-db_preflight.c b/src/stasis/anastasis-db_preflight.c
@@ -0,0 +1,58 @@
+/*
+ This file is part of Anastasis
+ 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 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_preflight.c
+ * @brief preflight check for the Anastasis database
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/preflight.h"
+
+
+enum GNUNET_GenericReturnValue
+ANASTASIS_DB_preflight (void)
+{
+ struct GNUNET_PQ_ExecuteStatement es[] = {
+ GNUNET_PQ_make_execute ("ROLLBACK"),
+ GNUNET_PQ_EXECUTE_STATEMENT_END
+ };
+
+ if (NULL == pg->transaction_name)
+ {
+ GNUNET_PQ_reconnect_if_down (pg->conn);
+ return GNUNET_OK; /* all good */
+ }
+ if (GNUNET_OK ==
+ GNUNET_PQ_exec_statements (pg->conn,
+ es))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "BUG: Preflight check rolled back transaction `%s'!\n",
+ pg->transaction_name);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "BUG: Preflight check failed to rollback transaction `%s'!\n",
+ pg->transaction_name);
+ }
+ pg->transaction_name = NULL;
+ return GNUNET_NO;
+}
+
+
+/* end of anastasis-db_preflight.c */
diff --git a/src/stasis/anastasis-db_record_auth_iban_payment.c b/src/stasis/anastasis-db_record_auth_iban_payment.c
@@ -0,0 +1,76 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_record_auth_iban_payment.c
+ * @brief Anastasis database: record auth iban payment
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/record_auth_iban_payment.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Store inbound IBAN payment made for authentication.
+ *
+ * @param wire_reference unique identifier inside LibEuFin/Nexus
+ * @param wire_subject subject of the wire transfer
+ * @param amount how much was transferred
+ * @param debit_account account that was debited
+ * @param credit_account Anastasis operator account credited
+ * @param execution_date when was the transfer made
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_record_auth_iban_payment (
+ uint64_t wire_reference,
+ const char *wire_subject,
+ const struct TALER_Amount *amount,
+ const char *debit_account,
+ const char *credit_account,
+ struct GNUNET_TIME_Timestamp execution_date)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&wire_reference),
+ GNUNET_PQ_query_param_string (wire_subject),
+ 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_timestamp (&execution_date),
+ GNUNET_PQ_query_param_end
+ };
+
+ PREPARE ("store_auth_iban_payment_details",
+ "INSERT INTO anastasis_auth_iban_in "
+ "(wire_reference"
+ ",wire_subject"
+ ",credit"
+ ",debit_account_details"
+ ",credit_account_details"
+ ",execution_date"
+ ") VALUES "
+ "($1, $2, $3, $4, $5, $6);");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "store_auth_iban_payment_details",
+ params);
+}
+
+
+/* end of anastasis-db_record_auth_iban_payment.c */
diff --git a/src/stasis/anastasis-db_record_challenge_payment.c b/src/stasis/anastasis-db_record_challenge_payment.c
@@ -0,0 +1,67 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_record_challenge_payment.c
+ * @brief Anastasis database: record challenge payment
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/record_challenge_payment.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Store payment for challenge.
+ *
+ * @param truth_uuid identifier of the challenge to pay
+ * @param payment_secret payment secret which the user must provide with every upload
+ * @param amount how much we asked for
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_record_challenge_payment (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const struct ANASTASIS_PaymentSecretP *payment_secret,
+ const struct TALER_Amount *amount)
+{
+ 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 (pg->conn,
+ amount),
+ GNUNET_PQ_query_param_auto_from_type (payment_secret),
+ GNUNET_PQ_query_param_timestamp (&now),
+ GNUNET_PQ_query_param_end
+ };
+
+ PREPARE ("challenge_payment_insert",
+ "INSERT INTO anastasis_challenge_payment "
+ "(truth_uuid"
+ ",amount"
+ ",payment_identifier"
+ ",creation_date"
+ ") VALUES "
+ "($1, $2, $3, $4);");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "challenge_payment_insert",
+ params);
+}
+
+
+/* end of anastasis-db_record_challenge_payment.c */
diff --git a/src/stasis/anastasis-db_record_challenge_refund.c b/src/stasis/anastasis-db_record_challenge_refund.c
@@ -0,0 +1,63 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_record_challenge_refund.c
+ * @brief Anastasis database: record challenge refund
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/record_challenge_refund.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Store refund granted for challenge.
+ *
+ * @param truth_uuid identifier of the challenge to refund
+ * @param payment_secret payment secret which the user must provide with every upload
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_record_challenge_refund (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const struct ANASTASIS_PaymentSecretP *payment_secret)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (payment_secret),
+ GNUNET_PQ_query_param_auto_from_type (truth_uuid),
+ GNUNET_PQ_query_param_end
+ };
+
+ PREPARE ("challenge_refund_update",
+ "UPDATE anastasis_challenge_payment "
+ "SET"
+ " refunded=TRUE "
+ "WHERE"
+ " payment_identifier=$1"
+ " AND"
+ " paid=TRUE"
+ " AND"
+ " truth_uuid=$2;");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "challenge_refund_update",
+ params);
+}
+
+
+/* end of anastasis-db_record_challenge_refund.c */
diff --git a/src/stasis/anastasis-db_record_recdoc_payment.c b/src/stasis/anastasis-db_record_recdoc_payment.c
@@ -0,0 +1,155 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_record_recdoc_payment.c
+ * @brief Anastasis database: record recdoc payment
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/record_recdoc_payment.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Store payment. Used to begin a payment, not indicative
+ * that the payment actually was made. (That is done
+ * when we increment the account's lifetime.)
+ *
+ * @param account_pub anastasis's public key
+ * @param post_counter how many uploads does @a amount pay for
+ * @param payment_secret payment secret which the user must provide with every upload
+ * @param amount how much we asked for
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_record_recdoc_payment (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ uint32_t post_counter,
+ const struct ANASTASIS_PaymentSecretP *payment_secret,
+ const struct TALER_Amount *amount)
+{
+ 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 (pg->conn,
+ amount),
+ GNUNET_PQ_query_param_auto_from_type (payment_secret),
+ GNUNET_PQ_query_param_timestamp (&now),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ GNUNET_break (GNUNET_OK ==
+ ANASTASIS_DB_preflight ());
+ PREPARE ("user_select3",
+ "SELECT"
+ " expiration_date "
+ "FROM anastasis_user"
+ " WHERE user_id=$1"
+ " FOR UPDATE;");
+ PREPARE ("user_insert3",
+ "INSERT INTO anastasis_user "
+ "(user_id"
+ ",expiration_date"
+ ") VALUES "
+ "($1, $2);");
+ PREPARE ("recdoc_payment_insert",
+ "INSERT INTO anastasis_recdoc_payment "
+ "(user_id"
+ ",post_counter"
+ ",amount"
+ ",payment_identifier"
+ ",creation_date"
+ ") VALUES "
+ "($1, $2, $3, $4, $5);");
+
+ /* because of constraint at user_id, first we have to verify
+ if user exists, and if not, create one */
+ {
+ struct GNUNET_PQ_QueryParam iparams[] = {
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_timestamp ("expiration_date",
+ &expiration),
+ GNUNET_PQ_result_spec_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "user_select3",
+ iparams,
+ rs);
+ }
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ return qs;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ {
+ /* create new user with short lifetime */
+ struct GNUNET_TIME_Timestamp exp
+ = GNUNET_TIME_relative_to_timestamp (TRANSIENT_LIFETIME);
+ struct GNUNET_PQ_QueryParam iparams[] = {
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_timestamp (&exp),
+ GNUNET_PQ_query_param_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "user_insert3",
+ iparams);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ /* successful, continue below */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Created new account %s with transient life until %s\n",
+ TALER_B2S (account_pub),
+ GNUNET_TIME_timestamp2s (exp));
+ break;
+ }
+ }
+ /* continue below */
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ /* handle case below */
+ break;
+ }
+
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "recdoc_payment_insert",
+ params);
+}
+
+
+/* end of anastasis-db_record_recdoc_payment.c */
diff --git a/src/stasis/anastasis-db_record_truth_upload_payment.c b/src/stasis/anastasis-db_record_truth_upload_payment.c
@@ -0,0 +1,66 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_record_truth_upload_payment.c
+ * @brief Anastasis database: record truth upload payment
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/record_truth_upload_payment.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Record truth upload payment was made.
+ *
+ * @param uuid the truth's UUID
+ * @param amount the amount that was paid
+ * @param duration how long is the truth paid for
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_record_truth_upload_payment (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid,
+ const struct TALER_Amount *amount,
+ struct GNUNET_TIME_Relative 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 (pg->conn,
+ amount),
+ GNUNET_PQ_query_param_timestamp (&exp),
+ GNUNET_PQ_query_param_end
+ };
+
+ PREPARE ("truth_payment_insert",
+ "INSERT INTO anastasis_truth_payment "
+ "(truth_uuid"
+ ",amount"
+ ",expiration"
+ ") VALUES "
+ "($1, $2, $3);");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "truth_payment_insert",
+ params);
+}
+
+
+/* end of anastasis-db_record_truth_upload_payment.c */
diff --git a/src/stasis/anastasis-db_store_recovery_document.c b/src/stasis/anastasis-db_store_recovery_document.c
@@ -0,0 +1,312 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_store_recovery_document.c
+ * @brief Anastasis database: store recovery document
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/store_recovery_document.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Store encrypted recovery document.
+ *
+ * @param account_pub public key of the user's account
+ * @param account_sig signature affirming storage request
+ * @param recovery_data_hash hash of @a data
+ * @param recovery_data contains encrypted_recovery_document
+ * @param recovery_data_size size of data blob
+ * @param payment_secret identifier for the payment, used to later charge on uploads
+ * @param[out] version set to the version assigned to the document by the database
+ * @return transaction status, 0 if upload could not be finished because @a payment_secret
+ * did not have enough upload left; HARD error if @a payment_secret is unknown, ...
+ */
+enum ANASTASIS_DB_StoreStatus
+ANASTASIS_DB_store_recovery_document (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ const struct ANASTASIS_AccountSignatureP *account_sig,
+ 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)
+{
+ enum GNUNET_DB_QueryStatus qs;
+
+ GNUNET_break (GNUNET_OK ==
+ ANASTASIS_DB_preflight ());
+
+ PREPARE ("user_select5",
+ "SELECT"
+ " expiration_date "
+ "FROM anastasis_user"
+ " WHERE user_id=$1"
+ " FOR UPDATE;");
+ PREPARE ("latest_recovery_version_select2",
+ "SELECT"
+ " version"
+ ",recovery_data_hash"
+ ",expiration_date"
+ " FROM anastasis_recoverydocument"
+ " JOIN anastasis_user USING (user_id)"
+ " WHERE user_id=$1"
+ " ORDER BY version DESC"
+ " LIMIT 1;");
+ PREPARE ("postcounter_select",
+ "SELECT"
+ " post_counter"
+ " FROM anastasis_recdoc_payment"
+ " WHERE user_id=$1"
+ " AND payment_identifier=$2;");
+ PREPARE ("postcounter_update",
+ "UPDATE"
+ " anastasis_recdoc_payment"
+ " SET"
+ " post_counter=$1"
+ " WHERE user_id =$2"
+ " AND payment_identifier=$3;");
+ PREPARE ("recovery_document_insert",
+ "INSERT INTO anastasis_recoverydocument "
+ "(user_id"
+ ",version"
+ ",account_sig"
+ ",recovery_data_hash"
+ ",recovery_data"
+ ",recovery_meta_data"
+ ",creation_date"
+ ") VALUES "
+ "($1, $2, $3, $4, $5, $6, $7);");
+ for (unsigned int retry = 0; retry<MAX_RETRIES; retry++)
+ {
+ if (GNUNET_OK !=
+ ANASTASIS_DB_start (
+ "store_recovery_document"))
+ {
+ GNUNET_break (0);
+ return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
+ }
+ /* get the current version and hash of the latest recovery document
+ for this account */
+ {
+ struct GNUNET_HashCode dh;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint32 ("version",
+ version),
+ GNUNET_PQ_result_spec_auto_from_type ("recovery_data_hash",
+ &dh),
+ GNUNET_PQ_result_spec_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (
+ pg->conn,
+ "latest_recovery_version_select2",
+ params,
+ rs);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ ANASTASIS_DB_rollback ();
+ return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ *version = 1;
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ /* had an existing recovery_data, is it identical? */
+ if (0 == GNUNET_memcmp (&dh,
+ recovery_data_hash))
+ {
+ /* Yes. Previous identical recovery data exists */
+ ANASTASIS_DB_rollback ();
+ return ANASTASIS_DB_STORE_STATUS_NO_RESULTS;
+ }
+ (*version)++;
+ break;
+ default:
+ GNUNET_break (0);
+ ANASTASIS_DB_rollback ();
+ return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
+ }
+ }
+
+ /* First, check if account exists */
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "user_select5",
+ params,
+ rs);
+ }
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ ANASTASIS_DB_rollback ();
+ return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ ANASTASIS_DB_rollback ();
+ return ANASTASIS_DB_STORE_STATUS_PAYMENT_REQUIRED;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ /* handle interesting case below */
+ break;
+ }
+
+ {
+ uint32_t postcounter;
+
+ /* lookup if the user has enough uploads left and decrement */
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_auto_from_type (payment_secret),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint32 ("post_counter",
+ &postcounter),
+ GNUNET_PQ_result_spec_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "postcounter_select",
+ params,
+ rs);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ ANASTASIS_DB_rollback ();
+ return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ ANASTASIS_DB_rollback ();
+ return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+ }
+
+ if (0 == postcounter)
+ {
+ ANASTASIS_DB_rollback ();
+ return ANASTASIS_DB_STORE_STATUS_STORE_LIMIT_EXCEEDED;
+ }
+ /* Decrement the postcounter by one */
+ postcounter--;
+
+ /* Update the postcounter in the Database */
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint32 (&postcounter),
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_auto_from_type (payment_secret),
+ GNUNET_PQ_query_param_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "postcounter_update",
+ params);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ ANASTASIS_DB_rollback ();
+ return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break (0);
+ ANASTASIS_DB_rollback ();
+ return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ default:
+ GNUNET_break (0);
+ ANASTASIS_DB_rollback ();
+ return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
+ }
+ }
+ }
+
+ /* 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),
+ GNUNET_PQ_query_param_auto_from_type (account_sig),
+ 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
+ };
+
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "recovery_document_insert",
+ params);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ ANASTASIS_DB_rollback ();
+ return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break (0);
+ ANASTASIS_DB_rollback ();
+ return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ qs = ANASTASIS_DB_commit ();
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto retry;
+ if (qs < 0)
+ return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
+ return ANASTASIS_DB_STORE_STATUS_SUCCESS;
+ }
+ }
+retry:
+ ANASTASIS_DB_rollback ();
+ }
+ return ANASTASIS_DB_STORE_STATUS_SOFT_ERROR;
+}
+
+
+/* end of anastasis-db_store_recovery_document.c */
diff --git a/src/stasis/anastasis-db_store_truth.c b/src/stasis/anastasis-db_store_truth.c
@@ -0,0 +1,80 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_store_truth.c
+ * @brief Anastasis database: store truth
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/store_truth.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Upload Truth, which contains the Truth and the KeyShare.
+ *
+ * @param truth_uuid the identifier for the Truth
+ * @param key_share_data contains information of an EncryptedKeyShare
+ * @param mime_type presumed mime type of data in @a encrypted_truth
+ * @param encrypted_truth contains the encrypted Truth which includes the ground truth i.e. H(challenge answer), phonenumber, SMS
+ * @param encrypted_truth_size the size of the Truth
+ * @param method name of method
+ * @param truth_expiration time till the according data will be stored
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_store_truth (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const struct ANASTASIS_CRYPTO_EncryptedKeyShareP *key_share_data,
+ const char *mime_type,
+ const void *encrypted_truth,
+ size_t encrypted_truth_size,
+ const char *method,
+ struct GNUNET_TIME_Relative truth_expiration)
+{
+ 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),
+ GNUNET_PQ_query_param_string (method),
+ GNUNET_PQ_query_param_fixed_size (encrypted_truth,
+ encrypted_truth_size),
+ GNUNET_PQ_query_param_string (mime_type),
+ GNUNET_PQ_query_param_timestamp (&expiration),
+ GNUNET_PQ_query_param_end
+ };
+
+ expiration = GNUNET_TIME_relative_to_timestamp (truth_expiration);
+ PREPARE ("truth_insert",
+ "INSERT INTO anastasis_truth "
+ "(truth_uuid"
+ ",key_share_data"
+ ",method_name"
+ ",encrypted_truth"
+ ",truth_mime"
+ ",expiration"
+ ") VALUES "
+ "($1, $2, $3, $4, $5, $6);");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "truth_insert",
+ params);
+}
+
+
+/* end of anastasis-db_store_truth.c */
diff --git a/src/stasis/anastasis-db_test_auth_iban_payment.c b/src/stasis/anastasis-db_test_auth_iban_payment.c
@@ -0,0 +1,156 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_test_auth_iban_payment.c
+ * @brief Anastasis database: test auth iban payment
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/test_auth_iban_payment.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+struct TestIbanContext
+{
+
+ /**
+ * Function to call on each wire transfer found.
+ */
+ ANASTASIS_DB_AuthIbanTransfercheck cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Value to return.
+ */
+ enum GNUNET_DB_QueryStatus qs;
+};
+
+
+/**
+ * Helper function for #postgres_test_auth_iban_payment().
+ * To be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls closure of type `struct TestIbanContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+test_auth_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct TestIbanContext *tic = cls;
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct TALER_Amount credit;
+ char *wire_subject;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_amount ("credit",
+ pg->currency,
+ &credit),
+ GNUNET_PQ_result_spec_string ("wire_subject",
+ &wire_subject),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ tic->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ return;
+ }
+ if (tic->cb (tic->cb_cls,
+ &credit,
+ wire_subject))
+ {
+ GNUNET_free (wire_subject);
+ tic->qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+ return;
+ }
+ GNUNET_free (wire_subject);
+ }
+}
+
+
+/**
+ * Function to check if we are aware of a wire transfer
+ * that satisfies the IBAN plugin's authentication check.
+ *
+ * @param cls closure
+ * @param debit_account which debit account to check
+ * @param earliest_date earliest date to check
+ * @param cb function to call on all entries found
+ * @param cb_cls closure for @a cb
+ * @return transaction status,
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a cb
+ * returned 'true' once
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if no
+ * wire transfers existed for which @a cb returned true
+ */
+
+
+/**
+ * Closure for #test_auth_cb.
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_test_auth_iban_payment (
+ const char *debit_account,
+ struct GNUNET_TIME_Timestamp earliest_date,
+ ANASTASIS_DB_AuthIbanTransfercheck cb,
+ void *cb_cls)
+{
+ struct TestIbanContext tic = {
+ .cb = cb,
+ .cb_cls = cb_cls
+ };
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (debit_account),
+ GNUNET_PQ_query_param_timestamp (&earliest_date),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ PREPARE ("test_auth_iban_payment",
+ "SELECT"
+ " credit"
+ ",wire_subject"
+ " FROM anastasis_auth_iban_in"
+ " WHERE debit_account_details=$1"
+ " AND execution_date>=$2;");
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "test_auth_iban_payment",
+ params,
+ &test_auth_cb,
+ &tic);
+ if (qs < 0)
+ return qs;
+ return tic.qs;
+}
+
+
+/* end of anastasis-db_test_auth_iban_payment.c */
diff --git a/src/stasis/anastasis-db_test_challenge_code_satisfied.c b/src/stasis/anastasis-db_test_challenge_code_satisfied.c
@@ -0,0 +1,69 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_test_challenge_code_satisfied.c
+ * @brief Anastasis database: test challenge code satisfied
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/test_challenge_code_satisfied.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Check if the 'satisfied' bit for the given challenge and code is
+ * 'true' and the challenge code is not yet expired.
+ *
+ * @param truth_uuid identification of the challenge which the code corresponds to
+ * @param code code which is now satisfied
+ * @return transaction status,
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the challenge code is not satisfied or expired
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the challenge code has been marked as satisfied
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_test_challenge_code_satisfied (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const uint64_t code,
+ struct GNUNET_TIME_Timestamp after)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (truth_uuid),
+ GNUNET_PQ_query_param_uint64 (&code),
+ GNUNET_PQ_query_param_timestamp (&after),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_end
+ };
+
+ 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;");
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "challengecode_test_satisfied",
+ params,
+ rs);
+}
+
+
+/* end of anastasis-db_test_challenge_code_satisfied.c */
diff --git a/src/stasis/anastasis-db_update_challenge_payment.c b/src/stasis/anastasis-db_update_challenge_payment.c
@@ -0,0 +1,65 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_update_challenge_payment.c
+ * @brief Anastasis database: update challenge payment
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/update_challenge_payment.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Update payment status of challenge
+ *
+ * @param truth_uuid which challenge received a payment
+ * @param payment_identifier proof of payment, must be unique and match pending payment
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_update_challenge_payment (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const struct ANASTASIS_PaymentSecretP *payment_identifier)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (payment_identifier),
+ GNUNET_PQ_query_param_auto_from_type (truth_uuid),
+ GNUNET_PQ_query_param_end
+ };
+
+ PREPARE ("challenge_payment_done",
+ "UPDATE anastasis_challenge_payment "
+ "SET"
+ " paid=TRUE "
+ "WHERE"
+ " payment_identifier=$1"
+ " AND"
+ " refunded=FALSE"
+ " AND"
+ " truth_uuid=$2"
+ " AND"
+ " paid=FALSE;");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "challenge_payment_done",
+ params);
+}
+
+
+/* end of anastasis-db_update_challenge_payment.c */
diff --git a/src/stasis/anastasis-db_update_lifetime.c b/src/stasis/anastasis-db_update_lifetime.c
@@ -0,0 +1,201 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_update_lifetime.c
+ * @brief Anastasis database: update lifetime
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/update_lifetime.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+/**
+ * Update account lifetime to the maximum of the current
+ * value and @a eol.
+ *
+ * @param account_pub which account received a payment
+ * @param payment_identifier proof of payment, must be unique and match pending payment
+ * @param eol for how long is the account now paid (absolute)
+ * @return transaction status
+ */
+// FIXME: what is the significant delta to increment_lifetime?
+// Should we combine these?
+enum GNUNET_DB_QueryStatus
+ANASTASIS_DB_update_lifetime (
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
+ const struct ANASTASIS_PaymentSecretP *payment_identifier,
+ struct GNUNET_TIME_Timestamp eol)
+{
+ enum GNUNET_DB_QueryStatus qs;
+
+ PREPARE ("user_select4",
+ "SELECT"
+ " expiration_date "
+ "FROM anastasis_user"
+ " WHERE user_id=$1"
+ " FOR UPDATE;");
+ PREPARE ("user_insert4",
+ "INSERT INTO anastasis_user "
+ "(user_id"
+ ",expiration_date"
+ ") VALUES "
+ "($1, $2);");
+ PREPARE ("user_update4",
+ "UPDATE anastasis_user"
+ " SET "
+ " expiration_date=$1"
+ " WHERE user_id=$2;");
+ PREPARE ("recdoc_payment_done2",
+ "UPDATE anastasis_recdoc_payment "
+ "SET"
+ " paid=TRUE "
+ "WHERE"
+ " payment_identifier=$1"
+ " AND"
+ " user_id=$2"
+ " AND"
+ " paid=FALSE;");
+ for (unsigned int retries = 0; retries<MAX_RETRIES; retries++)
+ {
+ if (GNUNET_OK !=
+ ANASTASIS_DB_start (
+ "update lifetime"))
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (payment_identifier),
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_end
+ };
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "recdoc_payment_done2",
+ params);
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto retry;
+ if (0 >= qs)
+ {
+ /* same payment made before, or unknown, or error
+ => no further action! */
+ ANASTASIS_DB_rollback ();
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Payment existed, lifetime of account %s unchanged\n",
+ TALER_B2S (account_pub));
+ return qs;
+ }
+ }
+
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_TIME_Timestamp expiration;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_timestamp ("expiration_date",
+ &expiration),
+ GNUNET_PQ_result_spec_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "user_select4",
+ params,
+ rs);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ ANASTASIS_DB_rollback ();
+ return qs;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ {
+ /* user does not exist, create new one */
+ struct GNUNET_PQ_QueryParam iparams[] = {
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_timestamp (&eol),
+ GNUNET_PQ_query_param_end
+ };
+
+ GNUNET_break (! GNUNET_TIME_absolute_is_never (eol.abs_time));
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "user_insert4",
+ iparams);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Created new account %s with expiration %s\n",
+ TALER_B2S (account_pub),
+ GNUNET_TIME_timestamp2s (eol));
+ }
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ {
+ /* user exists, update expiration_date */
+ struct GNUNET_PQ_QueryParam iparams[] = {
+ GNUNET_PQ_query_param_timestamp (&expiration),
+ GNUNET_PQ_query_param_auto_from_type (account_pub),
+ GNUNET_PQ_query_param_end
+ };
+
+ 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_update4",
+ iparams);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Updated account %s to new expiration %s\n",
+ TALER_B2S (account_pub),
+ GNUNET_TIME_timestamp2s (expiration));
+ }
+ break;
+ }
+ }
+
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ ANASTASIS_DB_rollback ();
+ return qs;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break (0);
+ ANASTASIS_DB_rollback ();
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+ qs = ANASTASIS_DB_commit ();
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto retry;
+ if (qs < 0)
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+retry:
+ ANASTASIS_DB_rollback ();
+ }
+ return GNUNET_DB_STATUS_SOFT_ERROR;
+}
+
+
+/* end of anastasis-db_update_lifetime.c */
diff --git a/src/stasis/anastasis-db_verify_challenge_code.c b/src/stasis/anastasis-db_verify_challenge_code.c
@@ -0,0 +1,211 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020-2022 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ 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
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file stasis/anastasis-db_verify_challenge_code.c
+ * @brief Anastasis database: verify challenge code
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis-db_pg.h"
+#include "anastasis/anastasis-database/verify_challenge_code.h"
+#include "anastasis/anastasis-database/transaction.h"
+#include "anastasis/anastasis-database/preflight.h"
+#include <taler/taler_pq_lib.h>
+
+
+struct CheckValidityContext
+{
+ /**
+ * Code to check for.
+ */
+ const struct GNUNET_HashCode *hashed_code;
+
+ /**
+ * Truth we are processing.
+ */
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid;
+
+ /**
+ * Set to the matching challenge code (if @e valid).
+ */
+ uint64_t code;
+
+ /**
+ * Set to true if a code matching @e hashed_code was found.
+ */
+ bool valid;
+
+ /**
+ * Set to true if a code matching @e hashed_code was set to 'satisfied' by the plugin.
+ */
+ bool satisfied;
+
+ /**
+ * Set to true if we had a database failure.
+ */
+ bool db_failure;
+
+};
+
+
+/**
+ * Helper function for #postgres_verify_challenge_code().
+ * To be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls closure of type `struct CheckValidityContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+check_valid_code (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct CheckValidityContext *cvc = cls;
+
+ for (unsigned int i = 0; i < num_results; i++)
+ {
+ uint64_t server_code;
+ uint8_t sat;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("code",
+ &server_code),
+ GNUNET_PQ_result_spec_auto_from_type ("satisfied",
+ &sat),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ 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;
+
+ ANASTASIS_hash_answer (server_code,
+ &shashed_code);
+ if (0 ==
+ 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);
+ }
+ else
+ {
+ /* count failures to prevent brute-force attacks */
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (cvc->truth_uuid),
+ GNUNET_PQ_query_param_uint64 (&server_code),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "challengecode_update_retry",
+ params);
+ if (qs <= 0)
+ {
+ GNUNET_break (0);
+ cvc->db_failure = true;
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * Verify the provided code with the code on the server.
+ * If the code matches the function will return with success, if the code
+ * does not match, the retry counter will be decreased by one.
+ *
+ * @param cls closure
+ * @param truth_uuid identification of the challenge which the code corresponds to
+ * @param hashed_code code which the user provided and wants to verify
+ * @param[out] code set to the original numeric code
+ * @param[out] satisfied set to true if the challenge is set to satisfied
+ * @return code validity status
+ */
+enum ANASTASIS_DB_CodeStatus
+ANASTASIS_DB_verify_challenge_code (
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const struct GNUNET_HashCode *hashed_code,
+ uint64_t *code,
+ bool *satisfied)
+{
+ struct CheckValidityContext cvc = {
+ .truth_uuid = truth_uuid,
+ .hashed_code = hashed_code,
+ };
+ struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (truth_uuid),
+ GNUNET_PQ_query_param_timestamp (&now),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ *satisfied = false;
+ PREPARE ("challengecode_update_retry",
+ "UPDATE anastasis_challengecode"
+ " SET retry_counter=retry_counter - 1"
+ " WHERE truth_uuid=$1"
+ " AND code=$2"
+ " AND retry_counter != 0;");
+ PREPARE ("challengecode_select",
+ "SELECT "
+ " code"
+ ",satisfied"
+ " FROM anastasis_challengecode"
+ " WHERE truth_uuid=$1"
+ " AND expiration_date > $2"
+ " AND retry_counter != 0;");
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "challengecode_select",
+ params,
+ &check_valid_code,
+ &cvc);
+ if ( (qs < 0) ||
+ (cvc.db_failure) )
+ return ANASTASIS_DB_CODE_STATUS_HARD_ERROR;
+ *code = cvc.code;
+ if (cvc.valid)
+ {
+ *satisfied = cvc.satisfied;
+ return ANASTASIS_DB_CODE_STATUS_VALID_CODE_STORED;
+ }
+ if (0 == qs)
+ return ANASTASIS_DB_CODE_STATUS_NO_RESULTS;
+ return ANASTASIS_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH;
+}
+
+
+/* end of anastasis-db_verify_challenge_code.c */
diff --git a/src/stasis/anastasis-dbinit.c b/src/stasis/anastasis-dbinit.c
@@ -1,6 +1,6 @@
/*
This file is part of Anastasis
- Copyright (C) 2019-2021 SARL
+ Copyright (C) 2019-2021, 2026 Anastasis SARL
Anastasis is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@@ -53,30 +53,28 @@ run (void *cls,
const char *cfgfile,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
- struct ANASTASIS_DatabasePlugin *plugin;
-
- if (NULL ==
- (plugin = ANASTASIS_DB_plugin_load (cfg,
- true)))
+ if (GNUNET_OK !=
+ ANASTASIS_DB_init (cfg))
{
fprintf (stderr,
- "Failed to initialize database plugin.\n");
+ "Failed to initialize database.\n");
global_ret = EXIT_NOTINSTALLED;
return;
}
if (reset_db)
{
- if (GNUNET_OK != plugin->drop_tables (plugin->cls))
+ if (GNUNET_OK !=
+ ANASTASIS_DB_drop_tables ())
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Could not drop tables as requested. Either database was not yet initialized, or permission denied. Consult the logs. Will still try to create new tables.\n");
}
}
if (GNUNET_OK !=
- plugin->create_tables (plugin->cls))
+ ANASTASIS_DB_create_tables ())
{
global_ret = EXIT_FAILURE;
- ANASTASIS_DB_plugin_unload (plugin);
+ ANASTASIS_DB_fini ();
return;
}
if (gc_db)
@@ -96,15 +94,15 @@ run (void *cls,
GNUNET_TIME_relative_multiply (
GNUNET_TIME_UNIT_YEARS,
10));
- if (0 > plugin->gc (plugin->cls,
- expire_backups,
- expire_payments))
+ if (0 > ANASTASIS_DB_gc (
+ expire_backups,
+ expire_payments))
{
fprintf (stderr,
"Garbage collection failed!\n");
}
}
- ANASTASIS_DB_plugin_unload (plugin);
+ ANASTASIS_DB_fini ();
}
diff --git a/src/stasis/anastasis_db_plugin.c b/src/stasis/anastasis_db_plugin.c
@@ -1,87 +0,0 @@
-/*
- This file is part of Anastasis
- Copyright (C) 2015, 2016 Anastasis SARL
-
- Anastasis is free software; you can redistribute it and/or modify it under the
- 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
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file stasis/anastasis_db_plugin.c
- * @brief Logic to load database plugin
- * @author Christian Grothoff
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- */
-#include "platform.h"
-#include "anastasis_database_lib.h"
-#include "anastasis_util_lib.h"
-#include <ltdl.h>
-
-
-struct ANASTASIS_DatabasePlugin *
-ANASTASIS_DB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg,
- bool skip_preflight)
-{
- char *plugin_name;
- char *lib_name;
- struct ANASTASIS_DatabasePlugin *plugin;
-
- if (GNUNET_SYSERR ==
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "anastasis",
- "db",
- &plugin_name))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "anastasis",
- "db");
- return NULL;
- }
- (void) GNUNET_asprintf (&lib_name,
- "libanastasis_plugin_db_%s",
- plugin_name);
- GNUNET_free (plugin_name);
- plugin = GNUNET_PLUGIN_load (ANASTASIS_project_data (),
- lib_name,
- (void *) cfg);
- if (NULL == plugin)
- {
- GNUNET_free (lib_name);
- return NULL;
- }
- plugin->library_name = lib_name;
- if ( (! skip_preflight) &&
- (GNUNET_OK !=
- plugin->preflight (plugin->cls)) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Database not ready. Try running anastasis-dbinit!\n");
- ANASTASIS_DB_plugin_unload (plugin);
- return NULL;
- }
- return plugin;
-}
-
-
-void
-ANASTASIS_DB_plugin_unload (struct ANASTASIS_DatabasePlugin *plugin)
-{
- char *lib_name;
-
- if (NULL == plugin)
- return;
- lib_name = plugin->library_name;
- GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name,
- plugin));
- GNUNET_free (lib_name);
-}
-
-
-/* end of anastasis_db_plugin.c */
diff --git a/src/stasis/meson.build b/src/stasis/meson.build
@@ -12,13 +12,56 @@ install_data(
install_data('stasis-postgres.conf', install_dir: pkgcfgdir)
+libanastasisdb_SOURCES = [
+ 'anastasis-db_pg.c',
+ 'anastasis-db_preflight.c',
+ 'anastasis-db_create_tables.c',
+ 'anastasis-db_drop_tables.c',
+ 'anastasis-db_gc.c',
+ 'anastasis-db_challenge_gc.c',
+ 'anastasis-db_check_challenge_payment.c',
+ 'anastasis-db_check_payment_identifier.c',
+ 'anastasis-db_check_truth_upload_paid.c',
+ 'anastasis-db_create_challenge_code.c',
+ 'anastasis-db_get_escrow_challenge.c',
+ 'anastasis-db_get_key_share.c',
+ 'anastasis-db_get_last_auth_iban_payment_row.c',
+ 'anastasis-db_get_latest_recovery_document.c',
+ 'anastasis-db_get_recovery_document.c',
+ 'anastasis-db_get_recovery_meta_data.c',
+ 'anastasis-db_increment_lifetime.c',
+ 'anastasis-db_lookup_account.c',
+ 'anastasis-db_lookup_challenge_payment.c',
+ 'anastasis-db_mark_challenge_code_satisfied.c',
+ 'anastasis-db_mark_challenge_sent.c',
+ 'anastasis-db_record_auth_iban_payment.c',
+ 'anastasis-db_record_challenge_payment.c',
+ 'anastasis-db_record_challenge_refund.c',
+ 'anastasis-db_record_recdoc_payment.c',
+ 'anastasis-db_record_truth_upload_payment.c',
+ 'anastasis-db_store_recovery_document.c',
+ 'anastasis-db_store_truth.c',
+ 'anastasis-db_test_auth_iban_payment.c',
+ 'anastasis-db_test_challenge_code_satisfied.c',
+ 'anastasis-db_update_challenge_payment.c',
+ 'anastasis-db_update_lifetime.c',
+ 'anastasis-db_verify_challenge_code.c',
+]
+
libanastasisdb = library(
'anastasisdb',
- ['anastasis_db_plugin.c'],
+ libanastasisdb_SOURCES,
soversion: solibversions['libanastasisdb']['soversion'],
version: solibversions['libanastasisdb']['soversion'],
install_rpath: rpath_option,
- dependencies: [gnunetutil_dep, gnunetpq_dep, pq_dep, libanastasisutil_dep],
+ dependencies: [
+ gnunetutil_dep,
+ gnunetpq_dep,
+ pq_dep,
+ talerpq_dep,
+ talerutil_dep,
+ libanastasisutil_dep,
+ ],
include_directories: [incdir, configuration_inc],
install: true,
install_dir: get_option('libdir'),
@@ -47,24 +90,6 @@ executable(
install: true,
)
-if pq_dep.found()
- shared_module(
- 'anastasis_plugin_db_postgres',
- ['plugin_anastasis_postgres.c'],
- dependencies: [
- libanastasisutil_dep,
- gnunetutil_dep,
- talerpq_dep,
- talerutil_dep,
- gnunetpq_dep,
- pq_dep,
- ],
- include_directories: [incdir, configuration_inc],
- install: true,
- install_dir: plugindir,
- )
-endif
-
test_anastasis_db_postgres = executable(
'test_anastasis_db-postgres',
['test_anastasis_db.c'],
@@ -75,6 +100,7 @@ test_anastasis_db_postgres = executable(
talerutil_dep,
talerpq_dep,
gnunetpq_dep,
+ json_dep,
],
include_directories: [incdir, configuration_inc],
build_by_default: false,
diff --git a/src/stasis/plugin_anastasis_postgres.c b/src/stasis/plugin_anastasis_postgres.c
@@ -1,2990 +0,0 @@
-/*
- This file is part of Anastasis
- 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 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
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file stasis/plugin_anastasis_postgres.c
- * @brief database helper functions for postgres used by GNU Anastasis
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "anastasis_database_plugin.h"
-#include "anastasis_database_lib.h"
-#include <taler/taler_pq_lib.h>
-
-/**
- * How long do we keep transient accounts open (those that have
- * not been paid at all, but are awaiting payment). This puts
- * a cap on how long users have to make a payment after a payment
- * request was generated.
- */
-#define TRANSIENT_LIFETIME GNUNET_TIME_UNIT_WEEKS
-
-/**
- * How often do we re-try if we run into a DB serialization error?
- */
-#define MAX_RETRIES 3
-
-
-/**
- * Type of the "cls" argument given to each of the functions in
- * our API.
- */
-struct PostgresClosure
-{
-
- /**
- * Postgres connection handle.
- */
- struct GNUNET_PQ_Context *conn;
-
- /**
- * Underlying configuration.
- */
- const struct GNUNET_CONFIGURATION_Handle *cfg;
-
- /**
- * Name of the currently active transaction, NULL if none is active.
- */
- const char *transaction_name;
-
- /**
- * Currency we accept payments in.
- */
- char *currency;
-
- /**
- * Prepared statements have been initialized.
- */
- bool init;
-};
-
-
-/**
- * Drop anastasis tables
- *
- * @param cls closure our `struct Plugin`
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
-static enum GNUNET_GenericReturnValue
-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",
- NULL,
- NULL,
- NULL);
- if (NULL == conn)
- return GNUNET_SYSERR;
- ret = GNUNET_PQ_exec_sql (conn,
- "drop");
- GNUNET_PQ_disconnect (conn);
- return ret;
-}
-
-
-/**
- * Initialize tables.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
-static enum GNUNET_GenericReturnValue
-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-",
- es,
- NULL);
- if (NULL == conn)
- return GNUNET_SYSERR;
- GNUNET_PQ_disconnect (conn);
- return GNUNET_OK;
-}
-
-
-/**
- * Establish connection to the database.
- *
- * @param cls plugin context
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
-static enum GNUNET_GenericReturnValue
-prepare_statements (void *cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_PreparedStatement ps[] = {
- GNUNET_PQ_make_prepare ("user_insert",
- "INSERT INTO anastasis_user "
- "(user_id"
- ",expiration_date"
- ") VALUES "
- "($1, $2);"),
- GNUNET_PQ_make_prepare ("do_commit",
- "COMMIT"),
- GNUNET_PQ_make_prepare ("user_select",
- "SELECT"
- " expiration_date "
- "FROM anastasis_user"
- " WHERE user_id=$1"
- " FOR UPDATE;"),
- GNUNET_PQ_make_prepare ("user_update",
- "UPDATE anastasis_user"
- " SET "
- " expiration_date=$1"
- " WHERE user_id=$2;"),
- GNUNET_PQ_make_prepare ("recdoc_payment_insert",
- "INSERT INTO anastasis_recdoc_payment "
- "(user_id"
- ",post_counter"
- ",amount"
- ",payment_identifier"
- ",creation_date"
- ") VALUES "
- "($1, $2, $3, $4, $5);"),
- GNUNET_PQ_make_prepare ("challenge_payment_insert",
- "INSERT INTO anastasis_challenge_payment "
- "(truth_uuid"
- ",amount"
- ",payment_identifier"
- ",creation_date"
- ") VALUES "
- "($1, $2, $3, $4);"),
- GNUNET_PQ_make_prepare ("truth_payment_insert",
- "INSERT INTO anastasis_truth_payment "
- "(truth_uuid"
- ",amount"
- ",expiration"
- ") VALUES "
- "($1, $2, $3);"),
- GNUNET_PQ_make_prepare ("recdoc_payment_done",
- "UPDATE anastasis_recdoc_payment "
- "SET"
- " paid=TRUE "
- "WHERE"
- " payment_identifier=$1"
- " AND"
- " user_id=$2"
- " AND"
- " paid=FALSE;"),
- GNUNET_PQ_make_prepare ("challenge_refund_update",
- "UPDATE anastasis_challenge_payment "
- "SET"
- " refunded=TRUE "
- "WHERE"
- " payment_identifier=$1"
- " AND"
- " paid=TRUE"
- " AND"
- " truth_uuid=$2;"),
- GNUNET_PQ_make_prepare ("challenge_payment_done",
- "UPDATE anastasis_challenge_payment "
- "SET"
- " paid=TRUE "
- "WHERE"
- " payment_identifier=$1"
- " AND"
- " refunded=FALSE"
- " AND"
- " truth_uuid=$2"
- " AND"
- " paid=FALSE;"),
- GNUNET_PQ_make_prepare ("recdoc_payment_select",
- "SELECT"
- " creation_date"
- ",post_counter"
- ",amount"
- ",paid"
- " FROM anastasis_recdoc_payment"
- " WHERE payment_identifier=$1;"),
- GNUNET_PQ_make_prepare ("truth_payment_select",
- "SELECT"
- " expiration"
- " FROM anastasis_truth_payment"
- " WHERE truth_uuid=$1"
- " AND expiration>$2;"),
- GNUNET_PQ_make_prepare ("challenge_payment_select",
- "SELECT"
- " creation_date"
- ",amount"
- ",paid"
- " FROM anastasis_challenge_payment"
- " WHERE payment_identifier=$1"
- " AND truth_uuid=$2"
- " AND refunded=FALSE"
- " AND counter>0;"),
- GNUNET_PQ_make_prepare ("challenge_pending_payment_select",
- "SELECT"
- " creation_date"
- ",payment_identifier"
- ",amount"
- " FROM anastasis_challenge_payment"
- " WHERE"
- " paid=FALSE"
- " AND"
- " refunded=FALSE"
- " AND"
- " truth_uuid=$1"
- " AND"
- " creation_date > $2;"),
- GNUNET_PQ_make_prepare ("recdoc_payments_select",
- "SELECT"
- " user_id"
- ",payment_identifier"
- ",amount"
- " FROM anastasis_recdoc_payment"
- " WHERE paid=FALSE;"),
- GNUNET_PQ_make_prepare ("gc_accounts",
- "DELETE FROM anastasis_user "
- "WHERE"
- " expiration_date < $1;"),
- GNUNET_PQ_make_prepare ("gc_recdoc_pending_payments",
- "DELETE FROM anastasis_recdoc_payment "
- "WHERE"
- " paid=FALSE"
- " AND"
- " creation_date < $1;"),
- GNUNET_PQ_make_prepare ("gc_challenge_pending_payments",
- "DELETE FROM anastasis_challenge_payment "
- "WHERE"
- " (paid=FALSE"
- " OR"
- " refunded=TRUE)"
- " AND"
- " creation_date < $1;"),
- GNUNET_PQ_make_prepare ("truth_insert",
- "INSERT INTO anastasis_truth "
- "(truth_uuid"
- ",key_share_data"
- ",method_name"
- ",encrypted_truth"
- ",truth_mime"
- ",expiration"
- ") VALUES "
- "($1, $2, $3, $4, $5, $6);"),
- GNUNET_PQ_make_prepare ("test_auth_iban_payment",
- "SELECT"
- " credit"
- ",wire_subject"
- " FROM anastasis_auth_iban_in"
- " WHERE debit_account_details=$1"
- " AND execution_date>=$2;"),
- GNUNET_PQ_make_prepare ("store_auth_iban_payment_details",
- "INSERT INTO anastasis_auth_iban_in "
- "(wire_reference"
- ",wire_subject"
- ",credit"
- ",debit_account_details"
- ",credit_account_details"
- ",execution_date"
- ") VALUES "
- "($1, $2, $3, $4, $5, $6);"),
- GNUNET_PQ_make_prepare ("recovery_document_insert",
- "INSERT INTO anastasis_recoverydocument "
- "(user_id"
- ",version"
- ",account_sig"
- ",recovery_data_hash"
- ",recovery_data"
- ",recovery_meta_data"
- ",creation_date"
- ") VALUES "
- "($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;"),
- 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"
- ",account_sig"
- ",recovery_data_hash"
- ",recovery_data"
- " FROM anastasis_recoverydocument"
- " WHERE user_id=$1"
- " ORDER BY version DESC"
- " LIMIT 1;"),
- GNUNET_PQ_make_prepare ("latest_recovery_version_select",
- "SELECT"
- " version"
- ",recovery_data_hash"
- ",expiration_date"
- " FROM anastasis_recoverydocument"
- " JOIN anastasis_user USING (user_id)"
- " WHERE user_id=$1"
- " ORDER BY version DESC"
- " LIMIT 1;"),
- GNUNET_PQ_make_prepare ("recoverydocument_select",
- "SELECT "
- " account_sig"
- ",recovery_data_hash"
- ",recovery_data"
- " FROM anastasis_recoverydocument"
- " WHERE user_id=$1"
- " AND version=$2;"),
- GNUNET_PQ_make_prepare ("postcounter_select",
- "SELECT"
- " post_counter"
- " FROM anastasis_recdoc_payment"
- " WHERE user_id=$1"
- " 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;"),
- GNUNET_PQ_make_prepare ("key_share_select",
- "SELECT "
- "key_share_data "
- "FROM "
- "anastasis_truth "
- "WHERE truth_uuid =$1;"),
- GNUNET_PQ_make_prepare ("challengecode_insert",
- "INSERT INTO anastasis_challengecode "
- "(truth_uuid"
- ",code"
- ",creation_date"
- ",expiration_date"
- ",retry_counter"
- ") VALUES "
- "($1, $2, $3, $4, $5);"),
- GNUNET_PQ_make_prepare ("challengecode_select",
- "SELECT "
- " code"
- ",satisfied"
- " FROM anastasis_challengecode"
- " WHERE truth_uuid=$1"
- " AND expiration_date > $2"
- " AND retry_counter != 0;"),
- GNUNET_PQ_make_prepare ("challengecode_set_satisfied",
- "UPDATE anastasis_challengecode"
- " SET satisfied=TRUE"
- " WHERE truth_uuid=$1"
- " AND code=$2"
- " AND creation_date IN"
- " (SELECT creation_date"
- " FROM anastasis_challengecode"
- " WHERE truth_uuid=$1"
- " AND code=$2"
- " ORDER BY creation_date DESC"
- " 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;"),
- GNUNET_PQ_make_prepare ("challengecode_select_meta",
- "SELECT "
- " code"
- ",retry_counter"
- ",retransmission_date"
- " FROM anastasis_challengecode"
- " WHERE truth_uuid=$1"
- " AND expiration_date > $2"
- " AND creation_date > $3"
- " ORDER BY creation_date DESC"
- " 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;"),
- 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;"),
- GNUNET_PQ_make_prepare ("challengecode_mark_sent",
- "UPDATE anastasis_challengecode"
- " SET retransmission_date=$3"
- " WHERE truth_uuid=$1"
- " AND code=$2"
- " AND creation_date IN"
- " (SELECT creation_date"
- " FROM anastasis_challengecode"
- " WHERE truth_uuid=$1"
- " AND code=$2"
- " ORDER BY creation_date DESC"
- " 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;"),
- GNUNET_PQ_make_prepare ("gc_challengecodes",
- "DELETE FROM anastasis_challengecode "
- "WHERE "
- "expiration_date < $1;"),
- GNUNET_PQ_PREPARED_STATEMENT_END
- };
-
- {
- enum GNUNET_GenericReturnValue ret;
-
- ret = GNUNET_PQ_prepare_statements (pg->conn,
- ps);
- if (GNUNET_OK != ret)
- return ret;
- pg->init = true;
- return GNUNET_OK;
- }
-}
-
-
-/**
- * Check that the database connection is still up.
- *
- * @param cls a `struct PostgresClosure` with connection to check
- */
-static void
-check_connection (void *cls)
-{
- struct PostgresClosure *pg = cls;
-
- GNUNET_PQ_reconnect_if_down (pg->conn);
-}
-
-
-/**
- * Connect to the database if the connection does not exist yet.
- *
- * @param pg the plugin-specific state
- * @return #GNUNET_OK on success
- */
-static enum GNUNET_GenericReturnValue
-internal_setup (struct PostgresClosure *pg)
-{
- if (NULL == pg->conn)
- {
-#if AUTO_EXPLAIN
- /* Enable verbose logging to see where queries do not
- properly use indices */
- struct GNUNET_PQ_ExecuteStatement es[] = {
- GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"),
- GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"),
- GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"),
- GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"),
- /* https://wiki.postgresql.org/wiki/Serializable suggests to really
- force the default to 'serializable' if SSI is to be used. */
- GNUNET_PQ_make_try_execute (
- "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[] = {
- 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_cfg2 (pg->cfg,
- "stasis-postgres",
- "statis-",
- es,
- NULL,
- GNUNET_PQ_FLAG_CHECK_CURRENT);
- if (NULL == db_conn)
- return GNUNET_SYSERR;
- pg->conn = db_conn;
- }
- if (NULL == pg->transaction_name)
- GNUNET_PQ_reconnect_if_down (pg->conn);
- if (pg->init)
- return GNUNET_OK;
- return prepare_statements (pg);
-}
-
-
-/**
- * Do a pre-flight check that we are not in an uncommitted transaction.
- * If we are, try to commit the previous transaction and output a warning.
- * Does not return anything, as we will continue regardless of the outcome.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @return #GNUNET_OK if everything is fine
- * #GNUNET_NO if a transaction was rolled back
- * #GNUNET_SYSERR on hard errors
- */
-static enum GNUNET_GenericReturnValue
-postgres_preflight (void *cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_ExecuteStatement es[] = {
- GNUNET_PQ_make_execute ("ROLLBACK"),
- GNUNET_PQ_EXECUTE_STATEMENT_END
- };
-
- if (! pg->init)
- {
- if (GNUNET_OK !=
- internal_setup (pg))
- return GNUNET_SYSERR;
- }
- if (NULL == pg->transaction_name)
- return GNUNET_OK; /* all good */
- if (GNUNET_OK ==
- GNUNET_PQ_exec_statements (pg->conn,
- es))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "BUG: Preflight check rolled back transaction `%s'!\n",
- pg->transaction_name);
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "BUG: Preflight check failed to rollback transaction `%s'!\n",
- pg->transaction_name);
- }
- pg->transaction_name = NULL;
- return GNUNET_NO;
-}
-
-
-/**
- * Start a transaction.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param name unique name identifying the transaction (for debugging),
- * must point to a constant
- * @return #GNUNET_OK on success
- */
-static enum GNUNET_GenericReturnValue
-begin_transaction (void *cls,
- const char *name)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_ExecuteStatement es[] = {
- GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"),
- GNUNET_PQ_EXECUTE_STATEMENT_END
- };
-
- check_connection (pg);
- GNUNET_break (GNUNET_OK ==
- postgres_preflight (pg));
- pg->transaction_name = name;
- if (GNUNET_OK !=
- GNUNET_PQ_exec_statements (pg->conn,
- es))
- {
- TALER_LOG_ERROR ("Failed to start transaction\n");
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
-* Roll back the current transaction of a database connection.
-*
-* @param cls the `struct PostgresClosure` with the plugin-specific state
-* @return #GNUNET_OK on success
-*/
-static void
-rollback (void *cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_ExecuteStatement es[] = {
- GNUNET_PQ_make_execute ("ROLLBACK"),
- GNUNET_PQ_EXECUTE_STATEMENT_END
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_exec_statements (pg->conn,
- es))
- {
- TALER_LOG_ERROR ("Failed to rollback transaction\n");
- GNUNET_break (0);
- }
- pg->transaction_name = NULL;
-}
-
-
-/**
- * Commit the current transaction of a database connection.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-commit_transaction (void *cls)
-{
- struct PostgresClosure *pg = cls;
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_PQ_QueryParam no_params[] = {
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "do_commit",
- no_params);
- pg->transaction_name = NULL;
- return qs;
-}
-
-
-/**
- * Register callback to be invoked on events of type @a es.
- *
- * @param cls database context to use
- * @param es specification of the event to listen for
- * @param timeout how long to wait for the event
- * @param cb function to call when the event happens, possibly
- * multiple times (until cancel is invoked)
- * @param cb_cls closure for @a cb
- * @return handle useful to cancel the listener
- */
-static struct GNUNET_DB_EventHandler *
-postgres_event_listen (void *cls,
- const struct GNUNET_DB_EventHeaderP *es,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_DB_EventCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
-
- return GNUNET_PQ_event_listen (pg->conn,
- es,
- timeout,
- cb,
- cb_cls);
-}
-
-
-/**
- * Stop notifications.
- *
- * @param eh handle to unregister.
- */
-static void
-postgres_event_listen_cancel (struct GNUNET_DB_EventHandler *eh)
-{
- GNUNET_PQ_event_listen_cancel (eh);
-}
-
-
-/**
- * Notify all that listen on @a es of an event.
- *
- * @param cls database context to use
- * @param es specification of the event to generate
- * @param extra additional event data provided
- * @param extra_size number of bytes in @a extra
- */
-static void
-postgres_event_notify (void *cls,
- const struct GNUNET_DB_EventHeaderP *es,
- const void *extra,
- size_t extra_size)
-{
- struct PostgresClosure *pg = cls;
-
- return GNUNET_PQ_event_notify (pg->conn,
- es,
- extra,
- extra_size);
-}
-
-
-/**
- * Function called to perform "garbage collection" on the
- * database, expiring records we no longer require. Deletes
- * all user records that are not paid up (and by cascade deletes
- * the associated recovery documents). Also deletes expired
- * truth and financial records older than @a fin_expire.
- *
- * @param cls closure
- * @param expire_backups backups older than the given time stamp should be garbage collected
- * @param expire_pending_payments payments still pending from since before
- * this value should be garbage collected
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_gc (void *cls,
- struct GNUNET_TIME_Absolute expire_backups,
- struct GNUNET_TIME_Absolute expire_pending_payments)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_absolute_time (&expire_backups),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_QueryParam params2[] = {
- GNUNET_PQ_query_param_absolute_time (&expire_pending_payments),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- GNUNET_break (GNUNET_OK ==
- postgres_preflight (pg));
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "gc_accounts",
- params);
- if (qs < 0)
- return qs;
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "gc_recdoc_pending_payments",
- params2);
-}
-
-
-/**
- * Store encrypted recovery document.
- *
- * @param cls closure
- * @param account_pub public key of the user's account
- * @param account_sig signature affirming storage request
- * @param recovery_data_hash hash of @a data
- * @param recovery_data contains encrypted_recovery_document
- * @param recovery_data_size size of data blob
- * @param payment_secret identifier for the payment, used to later charge on uploads
- * @param[out] version set to the version assigned to the document by the database
- * @return transaction status, 0 if upload could not be finished because @a payment_secret
- * did not have enough upload left; HARD error if @a payment_secret is unknown, ...
- */
-static enum ANASTASIS_DB_StoreStatus
-postgres_store_recovery_document (
- void *cls,
- const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
- const struct ANASTASIS_AccountSignatureP *account_sig,
- 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)
-{
- struct PostgresClosure *pg = cls;
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- GNUNET_break (GNUNET_OK ==
- postgres_preflight (pg));
- for (unsigned int retry = 0; retry<MAX_RETRIES; retry++)
- {
- if (GNUNET_OK !=
- begin_transaction (pg,
- "store_recovery_document"))
- {
- GNUNET_break (0);
- return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
- }
- /* get the current version and hash of the latest recovery document
- for this account */
- {
- struct GNUNET_HashCode dh;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint32 ("version",
- version),
- GNUNET_PQ_result_spec_auto_from_type ("recovery_data_hash",
- &dh),
- GNUNET_PQ_result_spec_end
- };
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "latest_recovery_version_select",
- params,
- rs);
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- GNUNET_break (0);
- rollback (pg);
- return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- goto retry;
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- *version = 1;
- break;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- /* had an existing recovery_data, is it identical? */
- if (0 == GNUNET_memcmp (&dh,
- recovery_data_hash))
- {
- /* Yes. Previous identical recovery data exists */
- rollback (pg);
- return ANASTASIS_DB_STORE_STATUS_NO_RESULTS;
- }
- (*version)++;
- break;
- default:
- GNUNET_break (0);
- rollback (pg);
- return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
- }
- }
-
- /* First, check if account exists */
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_end
- };
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "user_select",
- params,
- rs);
- }
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- rollback (pg);
- return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- goto retry;
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- rollback (pg);
- return ANASTASIS_DB_STORE_STATUS_PAYMENT_REQUIRED;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- /* handle interesting case below */
- break;
- }
-
- {
- uint32_t postcounter;
-
- /* lookup if the user has enough uploads left and decrement */
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_auto_from_type (payment_secret),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint32 ("post_counter",
- &postcounter),
- GNUNET_PQ_result_spec_end
- };
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "postcounter_select",
- params,
- rs);
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- rollback (pg);
- return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- goto retry;
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- rollback (pg);
- return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- break;
- }
- }
-
- if (0 == postcounter)
- {
- rollback (pg);
- return ANASTASIS_DB_STORE_STATUS_STORE_LIMIT_EXCEEDED;
- }
- /* Decrement the postcounter by one */
- postcounter--;
-
- /* Update the postcounter in the Database */
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint32 (&postcounter),
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_auto_from_type (payment_secret),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "postcounter_update",
- params);
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- GNUNET_break (0);
- rollback (pg);
- return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- goto retry;
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- GNUNET_break (0);
- rollback (pg);
- return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- break;
- default:
- GNUNET_break (0);
- rollback (pg);
- return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
- }
- }
- }
-
- /* 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),
- GNUNET_PQ_query_param_auto_from_type (account_sig),
- 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
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "recovery_document_insert",
- params);
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- rollback (pg);
- return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- goto retry;
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- GNUNET_break (0);
- rollback (pg);
- return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- qs = commit_transaction (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto retry;
- if (qs < 0)
- return ANASTASIS_DB_STORE_STATUS_HARD_ERROR;
- return ANASTASIS_DB_STORE_STATUS_SUCCESS;
- }
- }
-retry:
- rollback (pg);
- }
- return ANASTASIS_DB_STORE_STATUS_SOFT_ERROR;
-}
-
-
-/**
- * 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
- * @param payment_identifier proof of payment, must be unique and match pending payment
- * @param lifetime for how long is the account now paid (increment)
- * @param[out] paid_until set to the end of the lifetime after the operation
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_increment_lifetime (
- void *cls,
- const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
- const struct ANASTASIS_PaymentSecretP *payment_identifier,
- struct GNUNET_TIME_Relative lifetime,
- 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++)
- {
- if (GNUNET_OK !=
- begin_transaction (pg,
- "increment lifetime"))
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (payment_identifier),
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_end
- };
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "recdoc_payment_done",
- params);
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- rollback (pg);
- *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;
- }
- }
-
- {
- enum GNUNET_DB_QueryStatus qs2;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_TIME_Timestamp expiration;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_timestamp ("expiration_date",
- &expiration),
- GNUNET_PQ_result_spec_end
- };
-
- qs2 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "user_select",
- params,
- rs);
- switch (qs2)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- rollback (pg);
- return qs2;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- goto retry;
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- {
- /* inconsistent, cannot have recdoc payment but no user!? */
- GNUNET_break (0);
- rollback (pg);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- else
- {
- /* user does not exist, create new one */
- struct GNUNET_PQ_QueryParam iparams[] = {
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_timestamp (&expiration),
- GNUNET_PQ_query_param_end
- };
-
- 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",
- iparams);
- }
- break;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- {
- /* 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_TIME_timestamp2s (*paid_until));
- return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
- }
- else
- {
- /* user exists, payment is new, update expiration_date */
- struct GNUNET_PQ_QueryParam iparams[] = {
- GNUNET_PQ_query_param_timestamp (&expiration),
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_end
- };
-
- 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",
- iparams);
- }
- break;
- }
- }
-
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- rollback (pg);
- return qs;
- 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 GNUNET_DB_STATUS_HARD_ERROR;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Incremented lifetime of account %s to %s\n",
- TALER_B2S (account_pub),
- GNUNET_TIME_timestamp2s (*paid_until));
- return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
-retry:
- rollback (pg);
- }
- return GNUNET_DB_STATUS_SOFT_ERROR;
-}
-
-
-/**
- * Update account lifetime to the maximum of the current
- * value and @a eol.
- *
- * @param cls closure
- * @param account_pub which account received a payment
- * @param payment_identifier proof of payment, must be unique and match pending payment
- * @param eol for how long is the account now paid (absolute)
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_update_lifetime (
- void *cls,
- const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
- const struct ANASTASIS_PaymentSecretP *payment_identifier,
- struct GNUNET_TIME_Timestamp eol)
-{
- struct PostgresClosure *pg = cls;
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- for (unsigned int retries = 0; retries<MAX_RETRIES; retries++)
- {
- if (GNUNET_OK !=
- begin_transaction (pg,
- "update lifetime"))
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (payment_identifier),
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_end
- };
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "recdoc_payment_done",
- params);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto retry;
- if (0 >= qs)
- {
- /* same payment made before, or unknown, or error
- => no further action! */
- rollback (pg);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Payment existed, lifetime of account %s unchanged\n",
- TALER_B2S (account_pub));
- return qs;
- }
- }
-
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_TIME_Timestamp expiration;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_timestamp ("expiration_date",
- &expiration),
- GNUNET_PQ_result_spec_end
- };
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "user_select",
- params,
- rs);
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- rollback (pg);
- return qs;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- goto retry;
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- {
- /* user does not exist, create new one */
- struct GNUNET_PQ_QueryParam iparams[] = {
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_timestamp (&eol),
- GNUNET_PQ_query_param_end
- };
-
- GNUNET_break (! GNUNET_TIME_absolute_is_never (eol.abs_time));
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "user_insert",
- iparams);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Created new account %s with expiration %s\n",
- TALER_B2S (account_pub),
- GNUNET_TIME_timestamp2s (eol));
- }
- break;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- {
- /* user exists, update expiration_date */
- struct GNUNET_PQ_QueryParam iparams[] = {
- GNUNET_PQ_query_param_timestamp (&expiration),
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_end
- };
-
- 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",
- iparams);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Updated account %s to new expiration %s\n",
- TALER_B2S (account_pub),
- GNUNET_TIME_timestamp2s (expiration));
- }
- break;
- }
- }
-
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- rollback (pg);
- return qs;
- 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 GNUNET_DB_STATUS_HARD_ERROR;
- return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
-retry:
- rollback (pg);
- }
- return GNUNET_DB_STATUS_SOFT_ERROR;
-}
-
-
-/**
- * Store payment. Used to begin a payment, not indicative
- * that the payment actually was made. (That is done
- * when we increment the account's lifetime.)
- *
- * @param cls closure
- * @param account_pub anastasis's public key
- * @param post_counter how many uploads does @a amount pay for
- * @param payment_secret payment secret which the user must provide with every upload
- * @param amount how much we asked for
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_record_recdoc_payment (
- void *cls,
- const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
- uint32_t post_counter,
- const struct ANASTASIS_PaymentSecretP *payment_secret,
- const struct TALER_Amount *amount)
-{
- struct PostgresClosure *pg = cls;
- 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 (pg->conn,
- amount),
- GNUNET_PQ_query_param_auto_from_type (payment_secret),
- GNUNET_PQ_query_param_timestamp (&now),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (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 */
- {
- struct GNUNET_PQ_QueryParam iparams[] = {
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_timestamp ("expiration_date",
- &expiration),
- GNUNET_PQ_result_spec_end
- };
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "user_select",
- iparams,
- rs);
- }
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- return qs;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- {
- /* create new user with short lifetime */
- struct GNUNET_TIME_Timestamp exp
- = GNUNET_TIME_relative_to_timestamp (TRANSIENT_LIFETIME);
- struct GNUNET_PQ_QueryParam iparams[] = {
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_timestamp (&exp),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "user_insert",
- iparams);
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- return GNUNET_DB_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- /* successful, continue below */
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Created new account %s with transient life until %s\n",
- TALER_B2S (account_pub),
- GNUNET_TIME_timestamp2s (exp));
- break;
- }
- }
- /* continue below */
- break;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- /* handle case below */
- break;
- }
-
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "recdoc_payment_insert",
- params);
-}
-
-
-/**
- * Record truth upload payment was made.
- *
- * @param cls closure
- * @param uuid the truth's UUID
- * @param amount the amount that was paid
- * @param duration how long is the truth paid for
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_record_truth_upload_payment (
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid,
- const struct TALER_Amount *amount,
- struct GNUNET_TIME_Relative duration)
-{
- struct PostgresClosure *pg = cls;
- 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 (pg->conn,
- amount),
- GNUNET_PQ_query_param_timestamp (&exp),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "truth_payment_insert",
- params);
-}
-
-
-/**
- * Inquire whether truth upload payment was made.
- *
- * @param cls closure
- * @param uuid the truth's UUID
- * @param[out] paid_until set for how long this truth is paid for
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_check_truth_upload_paid (
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid,
- struct GNUNET_TIME_Timestamp *paid_until)
-{
- struct PostgresClosure *pg = cls;
- 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_timestamp (&now),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_timestamp ("expiration",
- paid_until),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "truth_payment_select",
- params,
- rs);
-}
-
-
-/**
- * Store payment for challenge.
- *
- * @param cls closure
- * @param truth_uuid identifier of the challenge to pay
- * @param payment_secret payment secret which the user must provide with every upload
- * @param amount how much we asked for
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_record_challenge_payment (
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- const struct ANASTASIS_PaymentSecretP *payment_secret,
- const struct TALER_Amount *amount)
-{
- struct PostgresClosure *pg = cls;
- 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 (pg->conn,
- amount),
- GNUNET_PQ_query_param_auto_from_type (payment_secret),
- GNUNET_PQ_query_param_timestamp (&now),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "challenge_payment_insert",
- params);
-}
-
-
-/**
- * Store refund granted for challenge.
- *
- * @param cls closure
- * @param truth_uuid identifier of the challenge to refund
- * @param payment_secret payment secret which the user must provide with every upload
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_record_challenge_refund (
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- const struct ANASTASIS_PaymentSecretP *payment_secret)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (payment_secret),
- GNUNET_PQ_query_param_auto_from_type (truth_uuid),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "challenge_refund_update",
- params);
-}
-
-
-/**
- * Store inbound IBAN payment made for authentication.
- *
- * @param cls closure
- * @param wire_reference unique identifier inside LibEuFin/Nexus
- * @param wire_subject subject of the wire transfer
- * @param amount how much was transferred
- * @param debit_account account that was debited
- * @param credit_account Anastasis operator account credited
- * @param execution_date when was the transfer made
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_record_auth_iban_payment (
- void *cls,
- uint64_t wire_reference,
- const char *wire_subject,
- const struct TALER_Amount *amount,
- const char *debit_account,
- const char *credit_account,
- 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 (pg->conn,
- amount),
- GNUNET_PQ_query_param_string (debit_account),
- GNUNET_PQ_query_param_string (credit_account),
- GNUNET_PQ_query_param_timestamp (&execution_date),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "store_auth_iban_payment_details",
- params);
-}
-
-
-/**
- * Closure for #test_auth_cb.
- */
-struct TestIbanContext
-{
-
- /**
- * Plugin context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Function to call on each wire transfer found.
- */
- ANASTASIS_DB_AuthIbanTransfercheck cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Value to return.
- */
- enum GNUNET_DB_QueryStatus qs;
-};
-
-
-/**
- * Helper function for #postgres_test_auth_iban_payment().
- * To be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls closure of type `struct TestIbanContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-test_auth_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct TestIbanContext *tic = cls;
- struct PostgresClosure *pg = tic->pg;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- struct TALER_Amount credit;
- char *wire_subject;
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_result_spec_amount ("credit",
- pg->currency,
- &credit),
- GNUNET_PQ_result_spec_string ("wire_subject",
- &wire_subject),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- tic->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- if (tic->cb (tic->cb_cls,
- &credit,
- wire_subject))
- {
- GNUNET_free (wire_subject);
- tic->qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
- return;
- }
- GNUNET_free (wire_subject);
- }
-}
-
-
-/**
- * Function to check if we are aware of a wire transfer
- * that satisfies the IBAN plugin's authentication check.
- *
- * @param cls closure
- * @param debit_account which debit account to check
- * @param earliest_date earliest date to check
- * @param cb function to call on all entries found
- * @param cb_cls closure for @a cb
- * @return transaction status,
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a cb
- * returned 'true' once
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if no
- * wire transfers existed for which @a cb returned true
- */
-static enum GNUNET_DB_QueryStatus
-postgres_test_auth_iban_payment (
- void *cls,
- const char *debit_account,
- struct GNUNET_TIME_Timestamp earliest_date,
- ANASTASIS_DB_AuthIbanTransfercheck cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct TestIbanContext tic = {
- .cb = cb,
- .cb_cls = cb_cls,
- .pg = pg
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (debit_account),
- GNUNET_PQ_query_param_timestamp (&earliest_date),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "test_auth_iban_payment",
- params,
- &test_auth_cb,
- &tic);
- if (qs < 0)
- return qs;
- return tic.qs;
-}
-
-
-/**
- * Function to check the last known IBAN payment.
- *
- * @param cls closure
- * @param credit_account which credit account to check
- * @param[out] last_row set to the last known row
- * @return transaction status,
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a cb
- * returned 'true' once
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if no
- * wire transfers existed for which @a cb returned true
- */
-static enum GNUNET_DB_QueryStatus
-postgres_get_last_auth_iban_payment_row (
- void *cls,
- const char *credit_account,
- uint64_t *last_row)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (credit_account),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("wire_reference",
- last_row),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "get_last_auth_iban_payment",
- params,
- rs);
-}
-
-
-/**
- * Check payment identifier. Used to check if a payment identifier given by
- * the user is valid (existing and paid).
- *
- * @param cls closure
- * @param payment_secret payment secret which the user must provide with every upload
- * @param truth_uuid which truth should we check the payment status of
- * @param[out] paid bool value to show if payment is paid
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_check_challenge_payment (
- void *cls,
- const struct ANASTASIS_PaymentSecretP *payment_secret,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- bool *paid)
-{
- struct PostgresClosure *pg = cls;
- uint8_t paid8;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (payment_secret),
- GNUNET_PQ_query_param_auto_from_type (truth_uuid),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("paid",
- &paid8),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "challenge_payment_select",
- params,
- rs);
- *paid = (0 != paid8);
- return qs;
-}
-
-
-/**
- * Check payment identifier. Used to check if a payment identifier given by
- * the user is valid (existing and paid).
- *
- * @param cls closure
- * @param payment_secret payment secret which the user must provide with every upload
- * @param[out] paid bool value to show if payment is paid
- * @param[out] valid_counter bool value to show if post_counter is > 0
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_check_payment_identifier (
- void *cls,
- const struct ANASTASIS_PaymentSecretP *payment_secret,
- bool *paid,
- bool *valid_counter)
-{
- struct PostgresClosure *pg = cls;
- uint32_t counter;
- uint8_t paid8;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (payment_secret),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("paid",
- &paid8),
- GNUNET_PQ_result_spec_uint32 ("post_counter",
- &counter),
- GNUNET_PQ_result_spec_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "recdoc_payment_select",
- params,
- rs);
-
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
- {
- if (counter > 0)
- *valid_counter = true;
- else
- *valid_counter = false;
- *paid = (0 != paid8);
- }
- return qs;
-}
-
-
-/**
- * Upload Truth, which contains the Truth and the KeyShare.
- *
- * @param cls closure
- * @param truth_uuid the identifier for the Truth
- * @param key_share_data contains information of an EncryptedKeyShare
- * @param mime_type presumed mime type of data in @a encrypted_truth
- * @param encrypted_truth contains the encrypted Truth which includes the ground truth i.e. H(challenge answer), phonenumber, SMS
- * @param encrypted_truth_size the size of the Truth
- * @param method name of method
- * @param truth_expiration time till the according data will be stored
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_store_truth (
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- const struct ANASTASIS_CRYPTO_EncryptedKeyShareP *key_share_data,
- const char *mime_type,
- const void *encrypted_truth,
- size_t encrypted_truth_size,
- const char *method,
- struct GNUNET_TIME_Relative truth_expiration)
-{
- struct PostgresClosure *pg = cls;
- 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),
- GNUNET_PQ_query_param_string (method),
- GNUNET_PQ_query_param_fixed_size (encrypted_truth,
- encrypted_truth_size),
- GNUNET_PQ_query_param_string (mime_type),
- GNUNET_PQ_query_param_timestamp (&expiration),
- GNUNET_PQ_query_param_end
- };
-
-
- expiration = GNUNET_TIME_relative_to_timestamp (truth_expiration);
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "truth_insert",
- params);
-}
-
-
-/**
- * Get the encrypted truth to validate the challenge response
- *
- * @param cls closure
- * @param truth_uuid the identifier for the Truth
- * @param[out] truth contains the encrypted truth
- * @param[out] truth_size size of the encrypted truth
- * @param[out] truth_mime mime type of truth
- * @param[out] method type of the challenge
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_get_escrow_challenge (
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- void **truth,
- size_t *truth_size,
- char **truth_mime,
- char **method)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (truth_uuid),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_variable_size ("encrypted_truth",
- truth,
- truth_size),
- GNUNET_PQ_result_spec_string ("truth_mime",
- truth_mime),
- GNUNET_PQ_result_spec_string ("method_name",
- method),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "truth_select",
- params,
- rs);
-}
-
-
-/**
- * Lookup (encrypted) key share by @a truth_uuid.
- *
- * @param cls closure
- * @param truth_uuid the identifier for the Truth
- * @param[out] key_share contains the encrypted Keyshare
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_get_key_share (
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- struct ANASTASIS_CRYPTO_EncryptedKeyShareP *key_share)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (truth_uuid),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("key_share_data",
- key_share),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "key_share_select",
- params,
- rs);
-}
-
-
-/**
- * Check if an account exists, and if so, return the
- * current @a recovery_document_hash.
- *
- * @param cls closure
- * @param account_pub account identifier
- * @param[out] paid_until until when is the account paid up?
- * @param[out] recovery_data_hash set to hash of @a recovery document
- * @param[out] version set to the recovery policy version
- * @return transaction status
- */
-static enum ANASTASIS_DB_AccountStatus
-postgres_lookup_account (
- void *cls,
- const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
- struct GNUNET_TIME_Timestamp *paid_until,
- struct GNUNET_HashCode *recovery_data_hash,
- uint32_t *version)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- GNUNET_break (GNUNET_OK ==
- postgres_preflight (pg));
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- 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",
- version),
- GNUNET_PQ_result_spec_end
- };
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "latest_recovery_version_select",
- params,
- rs);
- }
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- return ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- GNUNET_break (0);
- return ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- break; /* handle interesting case below */
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- return ANASTASIS_DB_ACCOUNT_STATUS_VALID_HASH_RETURNED;
- }
-
- /* check if account exists */
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_timestamp ("expiration_date",
- paid_until),
- GNUNET_PQ_result_spec_end
- };
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "user_select",
- params,
- rs);
- }
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- return ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- GNUNET_break (0);
- return ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR;
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- /* indicates: no account */
- return ANASTASIS_DB_ACCOUNT_STATUS_PAYMENT_REQUIRED;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- /* indicates: no backup */
- *version = UINT32_MAX;
- memset (recovery_data_hash,
- 0,
- sizeof (*recovery_data_hash));
- return ANASTASIS_DB_ACCOUNT_STATUS_NO_RESULTS;
- default:
- GNUNET_break (0);
- return ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR;
- }
-}
-
-
-/**
- * Fetch latest recovery document for user.
- *
- * @param cls closure
- * @param account_pub public key of the user's account
- * @param account_sig signature
- * @param recovery_data_hash hash of the current recovery data
- * @param data_size size of data blob
- * @param data blob which contains the recovery document
- * @param[out] version set to the version number of the policy being returned
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_get_latest_recovery_document (
- void *cls,
- const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
- struct ANASTASIS_AccountSignatureP *account_sig,
- struct GNUNET_HashCode *recovery_data_hash,
- size_t *data_size,
- void **data,
- uint32_t *version)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint32 ("version",
- version),
- GNUNET_PQ_result_spec_auto_from_type ("account_sig",
- account_sig),
- GNUNET_PQ_result_spec_auto_from_type ("recovery_data_hash",
- recovery_data_hash),
- GNUNET_PQ_result_spec_variable_size ("recovery_data",
- data,
- data_size),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- GNUNET_break (GNUNET_OK ==
- postgres_preflight (pg));
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "latest_recoverydocument_select",
- params,
- rs);
-}
-
-
-/**
- * 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
- * @param account_pub public key of the user's account
- * @param version the version number of the policy the user requests
- * @param[out] account_sig signature
- * @param[out] recovery_data_hash hash of the current recovery data
- * @param[out] data_size size of data blob
- * @param[out] data blob which contains the recovery document
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_get_recovery_document (
- void *cls,
- const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
- uint32_t version,
- struct ANASTASIS_AccountSignatureP *account_sig,
- struct GNUNET_HashCode *recovery_data_hash,
- size_t *data_size,
- void **data)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (account_pub),
- GNUNET_PQ_query_param_uint32 (&version),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("account_sig",
- account_sig),
- GNUNET_PQ_result_spec_auto_from_type ("recovery_data_hash",
- recovery_data_hash),
- GNUNET_PQ_result_spec_variable_size ("recovery_data",
- data,
- data_size),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "recoverydocument_select",
- params,
- rs);
-}
-
-
-/**
- * Closure for check_valid_code().
- */
-struct CheckValidityContext
-{
- /**
- * Code to check for.
- */
- const struct GNUNET_HashCode *hashed_code;
-
- /**
- * Truth we are processing.
- */
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid;
-
- /**
- * Database context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Set to the matching challenge code (if @e valid).
- */
- uint64_t code;
-
- /**
- * Set to true if a code matching @e hashed_code was found.
- */
- bool valid;
-
- /**
- * Set to true if a code matching @e hashed_code was set to 'satisfied' by the plugin.
- */
- bool satisfied;
-
- /**
- * Set to true if we had a database failure.
- */
- bool db_failure;
-
-};
-
-
-/**
- * Helper function for #postgres_verify_challenge_code().
- * To be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls closure of type `struct CheckValidityContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-check_valid_code (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct CheckValidityContext *cvc = cls;
- struct PostgresClosure *pg = cvc->pg;
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- uint64_t server_code;
- uint8_t sat;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("code",
- &server_code),
- GNUNET_PQ_result_spec_auto_from_type ("satisfied",
- &sat),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- 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;
-
- ANASTASIS_hash_answer (server_code,
- &shashed_code);
- if (0 ==
- 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);
- }
- else
- {
- /* count failures to prevent brute-force attacks */
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (cvc->truth_uuid),
- GNUNET_PQ_query_param_uint64 (&server_code),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "challengecode_update_retry",
- params);
- if (qs <= 0)
- {
- GNUNET_break (0);
- cvc->db_failure = true;
- }
- }
- }
- }
-}
-
-
-/**
- * Verify the provided code with the code on the server.
- * If the code matches the function will return with success, if the code
- * does not match, the retry counter will be decreased by one.
- *
- * @param cls closure
- * @param truth_uuid identification of the challenge which the code corresponds to
- * @param hashed_code code which the user provided and wants to verify
- * @param[out] code set to the original numeric code
- * @param[out] satisfied set to true if the challenge is set to satisfied
- * @return code validity status
- */
-static enum ANASTASIS_DB_CodeStatus
-postgres_verify_challenge_code (
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- const struct GNUNET_HashCode *hashed_code,
- uint64_t *code,
- bool *satisfied)
-{
- struct PostgresClosure *pg = cls;
- struct CheckValidityContext cvc = {
- .truth_uuid = truth_uuid,
- .hashed_code = hashed_code,
- .pg = pg
- };
- struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (truth_uuid),
- GNUNET_PQ_query_param_timestamp (&now),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- *satisfied = false;
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "challengecode_select",
- params,
- &check_valid_code,
- &cvc);
- if ( (qs < 0) ||
- (cvc.db_failure) )
- return ANASTASIS_DB_CODE_STATUS_HARD_ERROR;
- *code = cvc.code;
- if (cvc.valid)
- {
- *satisfied = cvc.satisfied;
- return ANASTASIS_DB_CODE_STATUS_VALID_CODE_STORED;
- }
- if (0 == qs)
- return ANASTASIS_DB_CODE_STATUS_NO_RESULTS;
- return ANASTASIS_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH;
-}
-
-
-/**
- * Set the 'satisfied' bit for the given challenge and code to
- * 'true'.
- *
- * @param cls closure
- * @param truth_uuid identification of the challenge which the code corresponds to
- * @param code code which is now satisfied
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_mark_challenge_code_satisfied (
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- const uint64_t code)
-{
- 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_end
- };
-
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "challengecode_set_satisfied",
- params);
-}
-
-
-/**
- * Check if the 'satisfied' bit for the given challenge and code is
- * 'true' and the challenge code is not yet expired.
- *
- * @param cls closure
- * @param truth_uuid identification of the challenge which the code corresponds to
- * @param code code which is now satisfied
- * @return transaction status,
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the challenge code is not satisfied or expired
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the challenge code has been marked as satisfied
- */
-static enum GNUNET_DB_QueryStatus
-postgres_test_challenge_code_satisfied (
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- const uint64_t code,
- 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_timestamp (&after),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_end
- };
-
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "challengecode_test_satisfied",
- params,
- rs);
-}
-
-
-/**
- * Lookup pending payment for a certain challenge.
- *
- * @param cls closure
- * @param truth_uuid identification of the challenge
- * @param[out] payment_secret set to the challenge payment secret
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_challenge_payment (
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- struct ANASTASIS_PaymentSecretP *payment_secret)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
- 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_timestamp (&recent),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("payment_identifier",
- payment_secret),
- GNUNET_PQ_result_spec_end
- };
-
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "challenge_pending_payment_select",
- params,
- rs);
-}
-
-
-/**
- * Update payment status of challenge
- *
- * @param cls closure
- * @param truth_uuid which challenge received a payment
- * @param payment_identifier proof of payment, must be unique and match pending payment
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_update_challenge_payment (
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- const struct ANASTASIS_PaymentSecretP *payment_identifier)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (payment_identifier),
- GNUNET_PQ_query_param_auto_from_type (truth_uuid),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "challenge_payment_done",
- params);
-}
-
-
-/**
- * Create a new 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.
- *
- * @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 retry_counter amount of retries allowed
- * @param[out] retransmission_date when to next retransmit
- * @param[out] code set to the code which will be checked for later
- * @return transaction status,
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if we are out of valid tries,
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a code is now in the DB
- */
-static enum GNUNET_DB_QueryStatus
-postgres_create_challenge_code (
- void *cls,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- struct GNUNET_TIME_Relative rotation_period,
- struct GNUNET_TIME_Relative validity_period,
- uint32_t retry_counter,
- struct GNUNET_TIME_Timestamp *retransmission_date,
- uint64_t *code)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
- struct GNUNET_TIME_Timestamp expiration_date;
- struct GNUNET_TIME_Absolute ex_rot;
-
- check_connection (pg);
- 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++)
- {
- if (GNUNET_OK !=
- begin_transaction (pg,
- "create_challenge_code"))
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- {
- uint32_t old_retry_counter;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (truth_uuid),
- GNUNET_PQ_query_param_timestamp (&now),
- GNUNET_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_uint32 ("retry_counter",
- &old_retry_counter),
- GNUNET_PQ_result_spec_timestamp ("retransmission_date",
- retransmission_date),
- 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:
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "No active challenge found, creating a fresh one\n");
- break;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- if (0 == old_retry_counter)
- {
- 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);
- return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
- }
- rollback (pg);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "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,
- 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),
- 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
- };
- enum GNUNET_DB_QueryStatus qs;
-
- 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:
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Created fresh challenge with %u tries left\n",
- (unsigned int) retry_counter);
- break;
- }
- }
-
- {
- enum GNUNET_DB_QueryStatus qs;
-
- 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
- * @param payment_secret payment secret which the user must provide with every upload
- * @param truth_uuid the identifier for the challenge
- * @param code the challenge that was sent
- */
-static enum GNUNET_DB_QueryStatus
-postgres_mark_challenge_sent (
- void *cls,
- const struct ANASTASIS_PaymentSecretP *payment_secret,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
- uint64_t code)
-{
- struct PostgresClosure *pg = cls;
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- {
- 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),
- GNUNET_PQ_query_param_timestamp (&now),
- GNUNET_PQ_query_param_end
- };
-
- 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),
- GNUNET_PQ_query_param_auto_from_type (payment_secret),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "challengepayment_dec_counter",
- params);
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; /* probably was free */
- return qs;
- }
-}
-
-
-/**
- * Function called to remove all expired codes from the database.
- *
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_challenge_gc (void *cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Timestamp time_now = GNUNET_TIME_timestamp_get ();
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_timestamp (&time_now),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- GNUNET_break (GNUNET_OK ==
- postgres_preflight (pg));
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "gc_challengecodes",
- params);
-}
-
-
-/**
- * Initialize Postgres database subsystem.
- *
- * @param cls a configuration instance
- * @return NULL on error, otherwise a `struct TALER_ANASTASISDB_Plugin`
- */
-void *
-libanastasis_plugin_db_postgres_init (void *cls);
-
-/* declaration to fix compiler warning */
-void *
-libanastasis_plugin_db_postgres_init (void *cls)
-{
- struct GNUNET_CONFIGURATION_Handle *cfg = cls;
- struct PostgresClosure *pg;
- struct ANASTASIS_DatabasePlugin *plugin;
-
- pg = GNUNET_new (struct PostgresClosure);
- pg->cfg = cfg;
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "anastasis",
- "CURRENCY",
- &pg->currency))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "anastasis",
- "CURRENCY");
- GNUNET_PQ_disconnect (pg->conn);
- GNUNET_free (pg);
- return NULL;
- }
- plugin = GNUNET_new (struct ANASTASIS_DatabasePlugin);
- plugin->cls = pg;
- /* 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;
- plugin->preflight = &postgres_preflight;
- plugin->rollback = &rollback;
- plugin->commit = &commit_transaction;
- plugin->event_listen = &postgres_event_listen;
- plugin->event_listen_cancel = &postgres_event_listen_cancel;
- plugin->event_notify = &postgres_event_notify;
- plugin->store_recovery_document = &postgres_store_recovery_document;
- plugin->record_recdoc_payment = &postgres_record_recdoc_payment;
- plugin->store_truth = &postgres_store_truth;
- 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;
- plugin->increment_lifetime = &postgres_increment_lifetime;
- plugin->update_lifetime = &postgres_update_lifetime;
- plugin->start = &begin_transaction;
- plugin->check_connection = &check_connection;
- plugin->verify_challenge_code = &postgres_verify_challenge_code;
- plugin->mark_challenge_code_satisfied =
- &postgres_mark_challenge_code_satisfied;
- plugin->test_challenge_code_satisfied =
- &postgres_test_challenge_code_satisfied;
- plugin->create_challenge_code = &postgres_create_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;
- plugin->check_truth_upload_paid = &postgres_check_truth_upload_paid;
- plugin->record_challenge_payment = &postgres_record_challenge_payment;
- plugin->record_challenge_refund = &postgres_record_challenge_refund;
- plugin->check_challenge_payment = &postgres_check_challenge_payment;
- plugin->lookup_challenge_payment = &postgres_lookup_challenge_payment;
- plugin->update_challenge_payment = &postgres_update_challenge_payment;
- plugin->record_auth_iban_payment = &postgres_record_auth_iban_payment;
- plugin->test_auth_iban_payment = &postgres_test_auth_iban_payment;
- plugin->get_last_auth_iban_payment_row
- = &postgres_get_last_auth_iban_payment_row;
- return plugin;
-}
-
-
-/**
- * Shutdown Postgres database subsystem.
- *
- * @param cls a `struct ANASTASIS_DB_STATUS_Plugin`
- * @return NULL (always)
- */
-void *
-libanastasis_plugin_db_postgres_done (void *cls);
-
-/* declaration to fix compiler warning */
-void *
-libanastasis_plugin_db_postgres_done (void *cls)
-{
- struct ANASTASIS_DatabasePlugin *plugin = cls;
- struct PostgresClosure *pg = plugin->cls;
-
- GNUNET_PQ_disconnect (pg->conn);
- GNUNET_free (pg->currency);
- GNUNET_free (pg);
- GNUNET_free (plugin);
- return NULL;
-}
-
-
-/* end of plugin_anastasisdb_postgres.c */
diff --git a/src/stasis/test_anastasis_db.c b/src/stasis/test_anastasis_db.c
@@ -43,12 +43,6 @@
static int result;
/**
- * Handle to the plugin we are testing.
- */
-static struct ANASTASIS_DatabasePlugin *plugin;
-
-
-/**
* Main function that will be run by the scheduler.
*
* @param cls closure with config
@@ -88,21 +82,21 @@ run (void *cls)
.purpose.size = htonl (sizeof (usp))
};
- if (NULL == (plugin = ANASTASIS_DB_plugin_load (cfg,
- true)))
+ if (GNUNET_OK !=
+ ANASTASIS_DB_init (cfg))
{
result = 77;
return;
}
- (void) plugin->drop_tables (plugin->cls);
+ (void) ANASTASIS_DB_drop_tables ();
if (GNUNET_OK !=
- plugin->create_tables (plugin->cls))
+ ANASTASIS_DB_create_tables ())
{
result = 77;
return;
}
if (GNUNET_OK !=
- plugin->connect (plugin->cls))
+ ANASTASIS_DB_preflight ())
{
result = 77;
return;
@@ -129,115 +123,115 @@ run (void *cls)
memset (&key_share, 1, sizeof (key_share));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->store_truth (plugin->cls,
- &truth_uuid,
- &key_share,
- mime_type,
- "encrypted_truth",
- strlen ("encrypted_truth"),
- method,
- rel_time));
+ ANASTASIS_DB_store_truth (
+ &truth_uuid,
+ &key_share,
+ mime_type,
+ "encrypted_truth",
+ strlen ("encrypted_truth"),
+ method,
+ rel_time));
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
- plugin->check_payment_identifier (plugin->cls,
- &paymentSecretP,
- &paid,
- &valid_counter));
+ ANASTASIS_DB_check_payment_identifier (
+ &paymentSecretP,
+ &paid,
+ &valid_counter));
memset (&accountPubP, 2, sizeof (accountPubP));
memset (&accountSig, 3, sizeof (accountSig));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->record_recdoc_payment (plugin->cls,
- &accountPubP,
- post_counter,
- &paymentSecretP,
- &amount));
+ ANASTASIS_DB_record_recdoc_payment (
+ &accountPubP,
+ post_counter,
+ &paymentSecretP,
+ &amount));
{
struct GNUNET_TIME_Timestamp res_time;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->increment_lifetime (plugin->cls,
- &accountPubP,
- &paymentSecretP,
- rel_time,
- &res_time));
+ ANASTASIS_DB_increment_lifetime (
+ &accountPubP,
+ &paymentSecretP,
+ rel_time,
+ &res_time));
}
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->check_payment_identifier (plugin->cls,
- &paymentSecretP,
- &paid,
- &valid_counter));
+ ANASTASIS_DB_check_payment_identifier (
+ &paymentSecretP,
+ &paid,
+ &valid_counter));
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
- plugin->check_challenge_payment (plugin->cls,
- &paymentSecretP,
- &truth_uuid,
- &paid));
+ ANASTASIS_DB_check_challenge_payment (
+ &paymentSecretP,
+ &truth_uuid,
+ &paid));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->record_challenge_payment (plugin->cls,
- &truth_uuid,
- &paymentSecretP,
- &amount));
+ ANASTASIS_DB_record_challenge_payment (
+ &truth_uuid,
+ &paymentSecretP,
+ &amount));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->update_challenge_payment (plugin->cls,
- &truth_uuid,
- &paymentSecretP));
+ ANASTASIS_DB_update_challenge_payment (
+ &truth_uuid,
+ &paymentSecretP));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->check_challenge_payment (plugin->cls,
- &paymentSecretP,
- &truth_uuid,
- &paid));
+ ANASTASIS_DB_check_challenge_payment (
+ &paymentSecretP,
+ &truth_uuid,
+ &paid));
FAILIF (! paid);
FAILIF (ANASTASIS_DB_STORE_STATUS_SUCCESS !=
- plugin->store_recovery_document (plugin->cls,
- &accountPubP,
- &accountSig,
- &recoveryDataHash,
- recovery_data,
- strlen (recovery_data),
- "meta-data",
- strlen ("meta-data"),
- &paymentSecretP,
- &docVersion));
+ ANASTASIS_DB_store_recovery_document (
+ &accountPubP,
+ &accountSig,
+ &recoveryDataHash,
+ recovery_data,
+ strlen (recovery_data),
+ "meta-data",
+ strlen ("meta-data"),
+ &paymentSecretP,
+ &docVersion));
{
uint32_t vrs;
struct GNUNET_TIME_Timestamp exp;
FAILIF (ANASTASIS_DB_ACCOUNT_STATUS_VALID_HASH_RETURNED !=
- plugin->lookup_account (plugin->cls,
- &accountPubP,
- &exp,
- &r,
- &vrs));
+ ANASTASIS_DB_lookup_account (
+ &accountPubP,
+ &exp,
+ &r,
+ &vrs));
}
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->get_key_share (plugin->cls,
- &truth_uuid,
- &res_key_share));
+ ANASTASIS_DB_get_key_share (
+ &truth_uuid,
+ &res_key_share));
FAILIF (0 !=
GNUNET_memcmp (&res_key_share,
&key_share));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->get_recovery_document (plugin->cls,
- &accountPubP,
- recversion,
- &res_account_sig,
- &res_recovery_data_hash,
- &recoverydatasize,
- &res_recovery_data));
+ ANASTASIS_DB_get_recovery_document (
+ &accountPubP,
+ recversion,
+ &res_account_sig,
+ &res_recovery_data_hash,
+ &recoverydatasize,
+ &res_recovery_data));
FAILIF (0 != memcmp (res_recovery_data,
recovery_data,
strlen (recovery_data)));
GNUNET_free (res_recovery_data);
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->get_latest_recovery_document (plugin->cls,
- &accountPubP,
- &res_account_sig,
- &res_recovery_data_hash,
- &recoverydatasize,
- &res_recovery_data,
- &res_version));
+ ANASTASIS_DB_get_latest_recovery_document (
+ &accountPubP,
+ &res_account_sig,
+ &res_recovery_data_hash,
+ &recoverydatasize,
+ &res_recovery_data,
+ &res_version));
FAILIF (0 != memcmp (res_recovery_data,
recovery_data,
strlen (recovery_data)));
@@ -247,13 +241,13 @@ run (void *cls)
struct GNUNET_TIME_Timestamp rt;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->create_challenge_code (plugin->cls,
- &truth_uuid,
- GNUNET_TIME_UNIT_HOURS,
- GNUNET_TIME_UNIT_DAYS,
- 3, /* retry counter */
- &rt,
- &challenge_code));
+ ANASTASIS_DB_create_challenge_code (
+ &truth_uuid,
+ GNUNET_TIME_UNIT_HOURS,
+ GNUNET_TIME_UNIT_DAYS,
+ 3, /* retry counter */
+ &rt,
+ &challenge_code));
FAILIF (! GNUNET_TIME_absolute_is_zero (rt.abs_time));
}
{
@@ -261,13 +255,13 @@ run (void *cls)
uint64_t c2;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->create_challenge_code (plugin->cls,
- &truth_uuid,
- GNUNET_TIME_UNIT_HOURS,
- GNUNET_TIME_UNIT_DAYS,
- 3, /* retry counter */
- &rt,
- &c2));
+ ANASTASIS_DB_create_challenge_code (
+ &truth_uuid,
+ GNUNET_TIME_UNIT_HOURS,
+ GNUNET_TIME_UNIT_DAYS,
+ 3, /* retry counter */
+ &rt,
+ &c2));
FAILIF (c2 != challenge_code);
}
ANASTASIS_hash_answer (123,
@@ -277,32 +271,28 @@ run (void *cls)
uint64_t r_code;
FAILIF (ANASTASIS_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH !=
- plugin->verify_challenge_code (plugin->cls,
- &truth_uuid,
- &c_hash,
- &r_code,
- &sat));
+ ANASTASIS_DB_verify_challenge_code (
+ &truth_uuid,
+ &c_hash,
+ &r_code,
+ &sat));
ANASTASIS_hash_answer (challenge_code,
&c_hash);
FAILIF (ANASTASIS_DB_CODE_STATUS_VALID_CODE_STORED !=
- plugin->verify_challenge_code (plugin->cls,
- &truth_uuid,
- &c_hash,
- &r_code,
- &sat));
+ ANASTASIS_DB_verify_challenge_code (
+ &truth_uuid,
+ &c_hash,
+ &r_code,
+ &sat));
}
if (-1 == result)
result = 0;
drop:
GNUNET_break (GNUNET_OK ==
- plugin->drop_tables (plugin->cls));
- ANASTASIS_DB_plugin_unload (plugin);
- if (NULL != plugin)
- {
- plugin = NULL;
- }
+ ANASTASIS_DB_drop_tables ());
+ ANASTASIS_DB_fini ();
}
diff --git a/src/util/meson.build b/src/util/meson.build
@@ -41,7 +41,12 @@ executable(
test_anastasis_crypto = executable(
'test_anastasis_crypto',
['test_anastasis_crypto.c'],
- dependencies: [gnunetutil_dep, talerutil_dep, libanastasisutil_dep],
+ dependencies: [
+ gnunetutil_dep,
+ talerutil_dep,
+ libanastasisutil_dep,
+ json_dep,
+ ],
include_directories: [incdir, configuration_inc],
build_by_default: false,
install: false,
@@ -68,5 +73,3 @@ executable(
include_directories: [incdir, configuration_inc],
install: true,
)
-
-