From d1a301ebbf758b9f323584b59b87635d12940948 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 13 Aug 2021 22:50:30 +0200 Subject: -modify DB schema in preparation for IBAN auth method support --- src/include/anastasis_crypto_lib.h | 2 +- src/include/anastasis_database_plugin.h | 78 +++++++++++++++++- src/stasis/plugin_anastasis_postgres.c | 136 +++++++++++++++++++++++++++++++- src/stasis/stasis-0001.sql | 5 +- 4 files changed, 216 insertions(+), 5 deletions(-) diff --git a/src/include/anastasis_crypto_lib.h b/src/include/anastasis_crypto_lib.h index 8faf65a..6377baf 100644 --- a/src/include/anastasis_crypto_lib.h +++ b/src/include/anastasis_crypto_lib.h @@ -367,7 +367,7 @@ ANASTASIS_CRYPTO_recovery_document_encrypt ( /** * Decrypts the recovery document with AES256, the decryption key is generated with * the user identifier provided by the user and the salt "erd". The nonce and IV used for the encryption - * are the first 48Byte of the data. + * are the first 48 bytes of the data. * * @param id Hashed User input, used for the generation of the encryption key * @param enc_rec_doc contains the encrypted recovery document and the nonce and iv used for the encryption. diff --git a/src/include/anastasis_database_plugin.h b/src/include/anastasis_database_plugin.h index 45efb09..6b686e2 100644 --- a/src/include/anastasis_database_plugin.h +++ b/src/include/anastasis_database_plugin.h @@ -1,6 +1,6 @@ /* This file is part of Anastasis - Copyright (C) 2019 Anastasis SARL + Copyright (C) 2019-2021 Anastasis SARL Anastasis is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software @@ -240,6 +240,46 @@ struct ANASTASIS_DatabasePlugin (*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 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, + 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. * @@ -535,6 +575,41 @@ struct ANASTASIS_DatabasePlugin const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, const struct GNUNET_HashCode *hashed_code); + + /** + * 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 ANASTASIS_DB_CodeStatus + (*mark_challenge_code_satisfied)( + void *cls, + const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, + const 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 + * @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 ANASTASIS_DB_CodeStatus + (*test_challenge_code_satisfied)( + void *cls, + const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, + const uint64_t code); + + /** * 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 @@ -641,7 +716,6 @@ struct ANASTASIS_DatabasePlugin /** * Function called to remove all expired codes from the database. - * FIXME: maybe implement as part of @e gc() in the future. * * @return transaction status */ diff --git a/src/stasis/plugin_anastasis_postgres.c b/src/stasis/plugin_anastasis_postgres.c index de30db0..001578d 100644 --- a/src/stasis/plugin_anastasis_postgres.c +++ b/src/stasis/plugin_anastasis_postgres.c @@ -225,6 +225,66 @@ commit_transaction (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 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, + GNUNET_DB_EventCallback cb, + void *cb_cls) +{ + struct PostgresClosure *pg = cls; + + return GNUNET_PQ_event_listen (pg->conn, + es, + 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 @@ -1619,6 +1679,72 @@ postgres_verify_challenge_code ( } +/** + * 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 ANASTASIS_DB_CodeStatus +postgres_mark_challenge_code_satisfied ( + void *cls, + const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, + const uint64_t code) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (truth_uuid), + GNUNET_PQ_query_param_uint64 (&code), + GNUNET_PQ_query_param_absolute_time (&now), + 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 ANASTASIS_DB_CodeStatus +postgres_test_challenge_code_satisfied ( + void *cls, + const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, + const uint64_t code) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (truth_uuid), + GNUNET_PQ_query_param_uint64 (&code), + GNUNET_PQ_query_param_absolute_time (&now), + 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. * @@ -1876,7 +2002,6 @@ postgres_mark_challenge_sent ( /** * Function called to remove all expired codes from the database. - * FIXME maybe implemented as part of postgres_gc() in the future. * * @return transaction status */ @@ -2246,6 +2371,7 @@ libanastasis_plugin_db_postgres_init (void *cls) GNUNET_free (pg); return NULL; } + GNUNET_PQ_event_scheduler_start (pg->conn); plugin = GNUNET_new (struct ANASTASIS_DatabasePlugin); plugin->cls = pg; plugin->drop_tables = &postgres_drop_tables; @@ -2253,6 +2379,9 @@ libanastasis_plugin_db_postgres_init (void *cls) 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; @@ -2267,6 +2396,10 @@ libanastasis_plugin_db_postgres_init (void *cls) 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; @@ -2293,6 +2426,7 @@ libanastasis_plugin_db_postgres_done (void *cls) struct ANASTASIS_DatabasePlugin *plugin = cls; struct PostgresClosure *pg = plugin->cls; + GNUNET_PQ_event_scheduler_stop (pg->conn); GNUNET_PQ_disconnect (pg->conn); GNUNET_free (pg->currency); GNUNET_free (pg); diff --git a/src/stasis/stasis-0001.sql b/src/stasis/stasis-0001.sql index beb886d..87dde94 100644 --- a/src/stasis/stasis-0001.sql +++ b/src/stasis/stasis-0001.sql @@ -161,7 +161,8 @@ CREATE TABLE IF NOT EXISTS anastasis_challengecode creation_date INT8 NOT NULL, expiration_date INT8 NOT NULL, retransmission_date INT8 NOT NULL DEFAULT 0, - retry_counter INT4 NOT NULL); + retry_counter INT4 NOT NULL, + satisfied BOOLEAN NOT NULL DEFAULT FALSE); COMMENT ON TABLE anastasis_challengecode IS 'Stores a code which is checked for the authentication by SMS, E-Mail..'; COMMENT ON COLUMN anastasis_challengecode.truth_uuid @@ -176,6 +177,8 @@ COMMENT ON COLUMN anastasis_challengecode.expiration_date IS 'When will the code expire'; COMMENT ON COLUMN anastasis_challengecode.retry_counter IS 'How many tries are left for this code must be > 0'; +COMMENT ON COLUMN anastasis_challengecode.satisfied + IS 'Has this challenge been satisfied by the user, used if it is not enough for the user to know the code (like for video identification or SEPA authentication). For SMS/E-mail/Post verification, this field being FALSE does not imply that the user did not meet the challenge.'; CREATE INDEX IF NOT EXISTS anastasis_challengecode_uuid_index ON anastasis_challengecode -- cgit v1.2.3