diff options
Diffstat (limited to 'src/backenddb/pg_lookup_instances.c')
-rw-r--r-- | src/backenddb/pg_lookup_instances.c | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/src/backenddb/pg_lookup_instances.c b/src/backenddb/pg_lookup_instances.c new file mode 100644 index 00000000..323b1957 --- /dev/null +++ b/src/backenddb/pg_lookup_instances.c @@ -0,0 +1,343 @@ +/* + This file is part of TALER + Copyright (C) 2022, 2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file backenddb/pg_lookup_instances.c + * @brief Implementation of the lookup_instances function for Postgres + * @author Christian Grothoff + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_pq_lib.h> +#include "pg_lookup_instances.h" +#include "pg_helper.h" + + +/** + * Context for lookup_instances(). + */ +struct LookupInstancesContext +{ + /** + * Function to call with the results. + */ + TALER_MERCHANTDB_InstanceCallback cb; + + /** + * Closure for @e cb. + */ + void *cb_cls; + + /** + * Database context. + */ + struct PostgresClosure *pg; + + /** + * Instance settings, valid only during find_instances_cb(). + */ + struct TALER_MERCHANTDB_InstanceSettings is; + + /** + * Instance authentication settings, valid only during find_instances_cb(). + */ + struct TALER_MERCHANTDB_InstanceAuthSettings ias; + + /** + * Instance serial number, valid only during find_instances_cb(). + */ + uint64_t instance_serial; + + /** + * Public key of the current instance, valid only during find_instances_cb(). + */ + struct TALER_MerchantPublicKeyP merchant_pub; + + /** + * Set to the return value on errors. + */ + enum GNUNET_DB_QueryStatus qs; + + /** + * true if we only are interested in instances for which we have the private key. + */ + bool active_only; +}; + + +/** + * Helper function to run PREPARE() macro. + * + * @param pg closure to pass + * @return status of the preparation + */ +static enum GNUNET_DB_QueryStatus +prepare (struct PostgresClosure *pg) +{ + PREPARE (pg, + "lookup_instance_private_key", + "SELECT" + " merchant_priv" + " FROM merchant_keys" + " WHERE merchant_serial=$1"); + return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; +} + + +/** + * We are processing an instances lookup and have the @a accounts. + * Find the private key if possible, and invoke the callback. + * + * @param lic context we are handling + */ +static void +call_cb (struct LookupInstancesContext *lic) +{ + struct PostgresClosure *pg = lic->pg; + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint64 (&lic->instance_serial), + GNUNET_PQ_query_param_end + }; + struct TALER_MerchantPrivateKeyP merchant_priv; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("merchant_priv", + &merchant_priv), + GNUNET_PQ_result_spec_end + }; + + qs = prepare (pg); + if (qs < 0) + { + GNUNET_break (0); + lic->qs = GNUNET_DB_STATUS_HARD_ERROR; + return; + } + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "lookup_instance_private_key", + params, + rs); + if (qs < 0) + { + GNUNET_break (0); + lic->qs = GNUNET_DB_STATUS_HARD_ERROR; + return; + } + if ( (0 == qs) && + (lic->active_only) ) + return; /* skip, not interesting */ + lic->cb (lic->cb_cls, + &lic->merchant_pub, + (0 == qs) ? NULL : &merchant_priv, + &lic->is, + &lic->ias); +} + + +/** + * Function to be called with the results of a SELECT statement + * that has returned @a num_results results about instances. + * + * @param cls of type `struct FindInstancesContext *` + * @param result the postgres result + * @param num_results the number of results in @a result + */ +static void +lookup_instances_cb (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupInstancesContext *lic = cls; + struct PostgresClosure *pg = lic->pg; + + lic->qs = prepare (pg); + if (lic->qs < 0) + { + GNUNET_break (0); + return; + } + + for (unsigned int i = 0; i < num_results; i++) + { + bool no_auth; + bool no_salt; + uint32_t ut32; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint64 ("merchant_serial", + &lic->instance_serial), + GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", + &lic->merchant_pub), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_auto_from_type ("auth_hash", + &lic->ias.auth_hash), + &no_auth), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_auto_from_type ("auth_salt", + &lic->ias.auth_salt), + &no_salt), + GNUNET_PQ_result_spec_string ("merchant_id", + &lic->is.id), + GNUNET_PQ_result_spec_string ("merchant_name", + &lic->is.name), + GNUNET_PQ_result_spec_uint32 ("user_type", + &ut32), + TALER_PQ_result_spec_json ("address", + &lic->is.address), + TALER_PQ_result_spec_json ("jurisdiction", + &lic->is.jurisdiction), + GNUNET_PQ_result_spec_bool ("use_stefan", + &lic->is.use_stefan), + GNUNET_PQ_result_spec_relative_time ("default_wire_transfer_delay", + &lic->is.default_wire_transfer_delay), + GNUNET_PQ_result_spec_relative_time ("default_pay_delay", + &lic->is.default_pay_delay), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_string ("website", + &lic->is.website), + NULL), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_string ("email", + &lic->is.email), + NULL), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_string ("logo", + &lic->is.logo), + NULL), + GNUNET_PQ_result_spec_end + }; + + memset (&lic->ias.auth_salt, + 0, + sizeof (lic->ias.auth_salt)); + memset (&lic->ias.auth_hash, + 0, + sizeof (lic->ias.auth_hash)); + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + lic->qs = GNUNET_DB_STATUS_HARD_ERROR; + return; + } + lic->is.ut = (enum TALER_KYCLOGIC_KycUserType) ut32; + call_cb (lic); + GNUNET_PQ_cleanup_result (rs); + if (0 > lic->qs) + break; + } +} + + +enum GNUNET_DB_QueryStatus +TMH_PG_lookup_instances (void *cls, + bool active_only, + TALER_MERCHANTDB_InstanceCallback cb, + void *cb_cls) +{ + struct PostgresClosure *pg = cls; + struct LookupInstancesContext lic = { + .cb = cb, + .cb_cls = cb_cls, + .active_only = active_only, + .pg = pg + }; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_end + }; + enum GNUNET_DB_QueryStatus qs; + + check_connection (pg); + PREPARE (pg, + "lookup_instances", + "SELECT" + " merchant_serial" + ",merchant_pub" + ",auth_hash" + ",auth_salt" + ",merchant_id" + ",merchant_name" + ",user_type" + ",address" + ",jurisdiction" + ",use_stefan" + ",default_wire_transfer_delay" + ",default_pay_delay" + ",website" + ",email" + ",logo" + " FROM merchant_instances"); + qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, + "lookup_instances", + params, + &lookup_instances_cb, + &lic); + if (0 > lic.qs) + return lic.qs; + return qs; +} + + +enum GNUNET_DB_QueryStatus +TMH_PG_lookup_instance (void *cls, + const char *id, + bool active_only, + TALER_MERCHANTDB_InstanceCallback cb, + void *cb_cls) +{ + struct PostgresClosure *pg = cls; + struct LookupInstancesContext lic = { + .cb = cb, + .cb_cls = cb_cls, + .active_only = active_only, + .pg = pg + }; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (id), + GNUNET_PQ_query_param_end + }; + enum GNUNET_DB_QueryStatus qs; + + check_connection (pg); + PREPARE (pg, + "lookup_instance", + "SELECT" + " merchant_serial" + ",merchant_pub" + ",auth_hash" + ",auth_salt" + ",merchant_id" + ",merchant_name" + ",user_type" + ",address" + ",jurisdiction" + ",use_stefan" + ",default_wire_transfer_delay" + ",default_pay_delay" + ",website" + ",email" + ",logo" + " FROM merchant_instances" + " WHERE merchant_id=$1"); + qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, + "lookup_instance", + params, + &lookup_instances_cb, + &lic); + if (0 > lic.qs) + return lic.qs; + return qs; +} |