commit 908cb91c95b2fb52b5fa3bc31a6472187b84163b
parent 61f3336601d6fd6fdcf8abfc052902e5404d903e
Author: Christian Grothoff <christian@grothoff.org>
Date: Sun, 23 Jun 2024 13:39:18 +0200
-implement GET "/aml/$PUB/attributes/$H_PAYTO"
Diffstat:
10 files changed, 727 insertions(+), 2 deletions(-)
diff --git a/src/exchange/taler-exchange-httpd_aml-attributes-get.c b/src/exchange/taler-exchange-httpd_aml-attributes-get.c
@@ -0,0 +1,179 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_aml-attributes-get.c
+ * @brief Return summary information about KYC attributes
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include <pthread.h>
+#include "taler_json_lib.h"
+#include "taler_mhd_lib.h"
+#include "taler_signatures.h"
+#include "taler-exchange-httpd.h"
+#include "taler_exchangedb_plugin.h"
+#include "taler-exchange-httpd_aml-attributes-get.h"
+#include "taler-exchange-httpd_metrics.h"
+
+/**
+ * Maximum number of records we return in one request.
+ */
+#define MAX_RECORDS 1024
+
+/**
+ * Return AML account attributes.
+ *
+ * @param cls closure
+ * @param row_id current row in kyc_attributes table
+ * @param provider_name which provider collected the data, NULL for user upload
+ * @param collection_time when were the attributes collected
+ * @param attributes the collected attributes
+ */
+static void
+detail_cb (
+ void *cls,
+ uint64_t row_id,
+ const char *provider_name,
+ struct GNUNET_TIME_Timestamp collection_time,
+ size_t enc_attributes_size,
+ const void *enc_attributes)
+{
+ json_t *records = cls;
+ json_t *attrs;
+
+ attrs = TALER_CRYPTO_kyc_attributes_decrypt (&TEH_attribute_key,
+ enc_attributes,
+ enc_attributes_size);
+ if (NULL == attrs)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ GNUNET_assert (
+ 0 ==
+ json_array_append (
+ records,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_int64 ("rowid",
+ row_id),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("provider_name",
+ provider_name)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_steal ("attributes",
+ attrs)),
+ GNUNET_JSON_pack_timestamp ("collection_time",
+ collection_time)
+ )));
+}
+
+
+MHD_RESULT
+TEH_handler_aml_attributes_get (
+ struct TEH_RequestContext *rc,
+ const struct TALER_AmlOfficerPublicKeyP *officer_pub,
+ const char *const args[])
+{
+ int64_t limit = -20;
+ uint64_t offset;
+ struct TALER_PaytoHashP h_payto;
+
+ if ( (NULL == args[0]) ||
+ (NULL != args[1]) )
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (
+ rc->connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
+ rc->url);
+ }
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (args[0],
+ strlen (args[0]),
+ &h_payto,
+ sizeof (h_payto)))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (
+ rc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PATH_SEGMENT_MALFORMED,
+ "h_payto");
+ }
+
+ TALER_MHD_parse_request_snumber (rc->connection,
+ "limit",
+ &limit);
+ if (limit > 0)
+ offset = 0;
+ else
+ offset = INT64_MAX;
+ TALER_MHD_parse_request_number (rc->connection,
+ "offset",
+ &offset);
+ {
+ json_t *details;
+ enum GNUNET_DB_QueryStatus qs;
+
+ details = json_array ();
+ GNUNET_assert (NULL != details);
+ if (limit > MAX_RECORDS)
+ limit = MAX_RECORDS;
+ if (limit < -MAX_RECORDS)
+ limit = -MAX_RECORDS;
+ qs = TEH_plugin->select_aml_attributes (
+ TEH_plugin->cls,
+ &h_payto,
+ offset,
+ limit,
+ &detail_cb,
+ details);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ json_decref (details);
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (
+ rc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "select_aml_attributes");
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ json_decref (details);
+ return TALER_MHD_reply_static (
+ rc->connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+ return TALER_MHD_REPLY_JSON_PACK (
+ rc->connection,
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_array_steal ("details",
+ details));
+ }
+}
+
+
+/* end of taler-exchange-httpd_aml-attributes_get.c */
diff --git a/src/exchange/taler-exchange-httpd_aml-attributes-get.h b/src/exchange/taler-exchange-httpd_aml-attributes-get.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_aml-attributes-get.h
+ * @brief Handle /aml/$OFFICER_PUB/decision requests
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_AML_ATTRIBUTES_GET_H
+#define TALER_EXCHANGE_HTTPD_AML_ATTRIBUTES_GET_H
+
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Handle a GET "/aml/$OFFICER_PUB/attributes/$H_PAYTO" request. Parses the request
+ * details, checks the signatures and if appropriately authorized returns
+ * the matching decisions.
+ *
+ * @param rc request context
+ * @param officer_pub public key of the AML officer who made the request
+ * @param args GET arguments (should be the state)
+ * @return MHD result code
+ */
+MHD_RESULT
+TEH_handler_aml_attributes_get (
+ struct TEH_RequestContext *rc,
+ const struct TALER_AmlOfficerPublicKeyP *officer_pub,
+ const char *const args[]);
+
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_reserves_attest.c b/src/exchange/taler-exchange-httpd_reserves_attest.c
@@ -183,6 +183,11 @@ kyc_process_cb (void *cls,
attrs = TALER_CRYPTO_kyc_attributes_decrypt (&TEH_attribute_key,
enc_attributes,
enc_attributes_size);
+ if (NULL == attrs)
+ {
+ GNUNET_break (0);
+ return;
+ }
json_object_foreach (attrs, name, val)
{
bool requested = false;
diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am
@@ -153,6 +153,7 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_do_recoup.h pg_do_recoup.c \
pg_do_recoup_refresh.h pg_do_recoup_refresh.c \
pg_get_reserve_balance.h pg_get_reserve_balance.c \
+ pg_select_aml_attributes.h pg_select_aml_attributes.c \
pg_count_known_coins.h pg_count_known_coins.c \
pg_ensure_coin_known.h pg_ensure_coin_known.c \
pg_get_known_coin.h pg_get_known_coin.c \
diff --git a/src/exchangedb/pg_select_aml_attributes.c b/src/exchangedb/pg_select_aml_attributes.c
@@ -0,0 +1,163 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 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 exchangedb/pg_select_aml_attributes.c
+ * @brief Implementation of the select_aml_attributes function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_select_aml_attributes.h"
+#include "pg_helper.h"
+
+
+/**
+ * Closure for #handle_aml_result.
+ */
+struct AmlAttributeResultContext
+{
+ /**
+ * Function to call on each result.
+ */
+ TALER_EXCHANGEDB_AmlAttributeCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Plugin context.
+ */
+ struct PostgresClosure *pg;
+
+ /**
+ * Set to #GNUNET_SYSERR on serious errors.
+ */
+ enum GNUNET_GenericReturnValue status;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results. Helper function
+ * for #TEH_PG_select_aml_process().
+ *
+ * @param cls closure of type `struct AmlAttributeResultContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+handle_aml_attributes (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct AmlAttributeResultContext *ctx = cls;
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ uint64_t rowid;
+ char *provider_name;
+ struct GNUNET_TIME_Timestamp collection_time;
+ size_t enc_attributes_size;
+ void *enc_attributes;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("kyc_attributes_serial_id",
+ &rowid),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string ("provider",
+ &provider_name),
+ NULL),
+ GNUNET_PQ_result_spec_timestamp ("collection_time",
+ &collection_time),
+ GNUNET_PQ_result_spec_variable_size ("encrypted_attributes",
+ &enc_attributes,
+ &enc_attributes_size),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->status = GNUNET_SYSERR;
+ return;
+ }
+
+ ctx->cb (ctx->cb_cls,
+ rowid,
+ provider_name,
+ collection_time,
+ enc_attributes_size,
+ enc_attributes);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_aml_attributes (
+ void *cls,
+ const struct TALER_PaytoHashP *h_payto,
+ uint64_t offset,
+ int64_t limit,
+ TALER_EXCHANGEDB_AmlAttributeCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ uint64_t ulimit = (limit > 0) ? limit : -limit;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (h_payto),
+ GNUNET_PQ_query_param_uint64 (&offset),
+ GNUNET_PQ_query_param_uint64 (&ulimit),
+ GNUNET_PQ_query_param_end
+ };
+ struct AmlAttributeResultContext ctx = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .pg = pg,
+ .status = GNUNET_OK
+ };
+ enum GNUNET_DB_QueryStatus qs;
+ const char *stmt = (limit > 0)
+ ? "select_aml_attributes_inc"
+ : "select_aml_attributes_dec";
+
+ PREPARE (pg,
+ "select_aml_attributes_inc",
+ "SELECT"
+ " kyc_attributes_serial_id"
+ ",provider"
+ ",collection_time"
+ ",encrypted_attributes"
+ " FROM kyc_attributes"
+ " WHERE h_payto=$1"
+ " AND kyc_attributes_serial_id > $2"
+ " ORDER BY kyc_attributes_serial_id ASC"
+ " LIMIT $3");
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ stmt,
+ params,
+ &handle_aml_attributes,
+ &ctx);
+ if (GNUNET_OK != ctx.status)
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ return qs;
+}
diff --git a/src/exchangedb/pg_select_aml_attributes.h b/src/exchangedb/pg_select_aml_attributes.h
@@ -0,0 +1,51 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 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 exchangedb/pg_select_aml_attributes.h
+ * @brief implementation of the select_aml_attributes function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_AML_ATTRIBUTES_H
+#define PG_SELECT_AML_ATTRIBUTES_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+
+/**
+ * Lookup AML attributes of a particular account.
+ *
+ * @param cls closure
+ * @param h_payto which account should we return attributes for
+ * @param offset row to start from
+ * @param limit how many records to return (negative
+ * to go back in time, positive to go forward)
+ * @param cb callback to invoke on each match
+ * @param cb_cls closure for @a cb
+ * @return database transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_aml_attributes (
+ void *cls,
+ const struct TALER_PaytoHashP *h_payto,
+ uint64_t offset,
+ int64_t limit,
+ TALER_EXCHANGEDB_AmlAttributeCallback cb,
+ void *cb_cls);
+
+
+#endif
diff --git a/src/exchangedb/pg_select_aml_decisions.c b/src/exchangedb/pg_select_aml_decisions.c
@@ -0,0 +1,222 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 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 exchangedb/pg_select_aml_decisions.c
+ * @brief Implementation of the select_aml_decisions function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_select_aml_decisions.h"
+#include "pg_helper.h"
+
+
+/**
+ * Closure for #handle_aml_result.
+ */
+struct AmlProcessResultContext
+{
+ /**
+ * Function to call on each result.
+ */
+ TALER_EXCHANGEDB_AmlDecisionCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Plugin context.
+ */
+ struct PostgresClosure *pg;
+
+ /**
+ * Set to #GNUNET_SYSERR on serious errors.
+ */
+ enum GNUNET_GenericReturnValue status;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results. Helper function
+ * for #TEH_PG_select_aml_process().
+ *
+ * @param cls closure of type `struct AmlProcessResultContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+handle_aml_result (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct AmlProcessResultContext *ctx = cls;
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct TALER_PaytoHashP h_payto;
+ uint64_t rowid;
+ char *justification;
+ struct GNUNET_TIME_Timestamp decision_time;
+ struct GNUNET_TIME_Absolute expiration_time;
+ json_t *jproperties;
+ bool to_investigate;
+ bool is_active;
+ json_t *account_rules;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("outcome_serial_id",
+ &rowid),
+ GNUNET_PQ_result_spec_auto_from_type ("h_payto",
+ &h_payto),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string ("justification",
+ &justification),
+ NULL),
+ GNUNET_PQ_result_spec_timestamp ("decision_time",
+ &decision_time),
+ GNUNET_PQ_result_spec_absolute_time ("expiration_time",
+ &expiration_time),
+ TALER_PQ_result_spec_json ("jproperties",
+ &jproperties),
+ TALER_PQ_result_spec_json ("jnew_rules",
+ &account_rules),
+ GNUNET_PQ_result_spec_bool ("to_investigate",
+ &to_investigate),
+ GNUNET_PQ_result_spec_bool ("is_active",
+ &is_active),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->status = GNUNET_SYSERR;
+ return;
+ }
+ if (GNUNET_TIME_absolute_is_past (expiration_time))
+ is_active = false;
+ ctx->cb (ctx->cb_cls,
+ rowid,
+ justification,
+ &h_payto,
+ decision_time,
+ expiration_time,
+ jproperties,
+ to_investigate,
+ is_active,
+ account_rules);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_aml_decisions (
+ void *cls,
+ const struct TALER_PaytoHashP *h_payto,
+ enum TALER_EXCHANGE_YesNoAll investigation_only,
+ enum TALER_EXCHANGE_YesNoAll active_only,
+ uint64_t offset,
+ int64_t limit,
+ TALER_EXCHANGEDB_AmlDecisionCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ uint64_t ulimit = (limit > 0) ? limit : -limit;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_bool (NULL == h_payto),
+ NULL == h_payto
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_auto_from_type (h_payto),
+ GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL ==
+ investigation_only)),
+ GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES ==
+ investigation_only)),
+ GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL ==
+ active_only)),
+ GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES ==
+ active_only)),
+ GNUNET_PQ_query_param_uint64 (&offset),
+ GNUNET_PQ_query_param_uint64 (&ulimit),
+ GNUNET_PQ_query_param_end
+ };
+ struct AmlProcessResultContext ctx = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .pg = pg,
+ .status = GNUNET_OK
+ };
+ enum GNUNET_DB_QueryStatus qs;
+ const char *stmt = (limit > 0)
+ ? "select_aml_decisions_inc"
+ : "select_aml_decisions_dec";
+
+ PREPARE (pg,
+ "select_aml_decisions_inc",
+ "SELECT"
+ " outcome_serial_id"
+ ",h_payto"
+ ",justification"
+ ",decision_time"
+ ",expiration_time"
+ ",jproperties"
+ ",to_investigate"
+ ",is_active"
+ ",jnew_rules"
+ " FROM legitimization_outcomes"
+ " WHERE outcome_serial_id > $7"
+ " ($1 OR (h_payto = $2)) AND"
+ " ($3 OR (investigation = $4)) AND"
+ " ($5 OR (active = $6))"
+ " ORDER BY outcome_serial_id ASC"
+ " LIMIT $8");
+ PREPARE (pg,
+ "select_aml_decisions_dec",
+ "SELECT"
+ " outcome_serial_id"
+ ",h_payto"
+ ",justification"
+ ",decision_time"
+ ",expiration_time"
+ ",jproperties"
+ ",to_investigate"
+ ",is_active"
+ ",jnew_rules"
+ " FROM legitimization_outcomes"
+ " LEFT JOIN aml_history"
+ " ON (outcome_serial_id)"
+ " WHERE outcome_serial_id < $7"
+ " ($1 OR (h_payto = $2)) AND"
+ " ($3 OR (investigation = $4)) AND"
+ " ($5 OR (active = $6))"
+ " ORDER BY outcome_serial_id DESC"
+ " LIMIT $8");
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ stmt,
+ params,
+ &handle_aml_result,
+ &ctx);
+ if (GNUNET_OK != ctx.status)
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ return qs;
+}
diff --git a/src/exchangedb/pg_select_aml_decisions.h b/src/exchangedb/pg_select_aml_decisions.h
@@ -0,0 +1,54 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 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 exchangedb/pg_select_aml_decisions.h
+ * @brief implementation of the select_aml_decisions function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_AML_DECISIONS_H
+#define PG_SELECT_AML_DECISIONS_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+
+/**
+ * Lookup AML decisions that have a particular state.
+ *
+ * @param cls closure
+ * @param h_payto which account should we return the AML decision history for, NULL to return all accounts
+ * @param investigation_only filter by investigation state
+ * @param active_only filter for only active states
+ * @param offset row to start from
+ * @param limit how many records to return (negative
+ * to go back in time, positive to go forward)
+ * @param cb callback to invoke on each match
+ * @param cb_cls closure for @a cb
+ * @return database transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_aml_decisions (
+ void *cls,
+ const struct TALER_PaytoHashP *h_payto,
+ enum TALER_EXCHANGE_YesNoAll investigation_only,
+ enum TALER_EXCHANGE_YesNoAll active_only,
+ uint64_t offset,
+ int64_t limit,
+ TALER_EXCHANGEDB_AmlDecisionCallback cb,
+ void *cb_cls);
+
+#endif
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -56,6 +56,7 @@
#include "pg_select_account_merges_above_serial_id.h"
#include "pg_select_all_purse_decisions_above_serial_id.h"
#include "pg_select_purse.h"
+#include "pg_select_aml_attributes.h"
#include "pg_trigger_kyc_rule_for_account.h"
#include "pg_select_purse_deposits_above_serial_id.h"
#include "pg_select_purse_merges_above_serial_id.h"
@@ -730,6 +731,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_select_aml_decisions;
plugin->insert_signkey_revocation
= &TEH_PG_insert_signkey_revocation;
+ plugin->select_aml_attributes
+ = &TEH_PG_select_aml_attributes;
plugin->lookup_signkey_revocation
= &TEH_PG_lookup_signkey_revocation;
plugin->lookup_denomination_key
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
@@ -3545,7 +3545,8 @@ typedef void
* @param row_id current row in kyc_attributes table
* @param provider_name which provider collected the data, NULL for user upload
* @param collection_time when were the attributes collected
- * @param attributes the collected attributes
+ * @param enc_attributes_size size of @a enc_attributes
+ * @param enc_attributes the encrypted collected attributes
*/
typedef void
(*TALER_EXCHANGEDB_AmlAttributeCallback)(
@@ -3553,7 +3554,8 @@ typedef void
uint64_t row_id,
const char *provider_name,
struct GNUNET_TIME_Timestamp collection_time,
- const json_t *attributes);
+ size_t enc_attributes_size,
+ const void *enc_attributes);
/**