commit c983fb533c9a1ad5ab780b932c52a176994c08e1
parent a1cf5ed17a55dd3bb43b97a476dd1d64c646c614
Author: Christian Grothoff <christian@grothoff.org>
Date: Sat, 27 Dec 2025 22:02:50 +0100
changing to new auth design as discussed with Florian
Diffstat:
13 files changed, 258 insertions(+), 53 deletions(-)
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
@@ -232,6 +232,8 @@ taler_merchant_httpd_SOURCES = \
taler-merchant-httpd_post-orders-ID-refund.h \
taler-merchant-httpd_post-using-templates.c \
taler-merchant-httpd_post-using-templates.h \
+ taler-merchant-httpd_post-reports-ID.c \
+ taler-merchant-httpd_post-reports-ID.h \
taler-merchant-httpd_private-get-statistics-amount-SLUG.c \
taler-merchant-httpd_private-get-statistics-amount-SLUG.h \
taler-merchant-httpd_private-get-statistics-counter-SLUG.c \
@@ -354,6 +356,7 @@ taler_merchant_report_generator_LDADD = \
$(top_builddir)/src/util/libtalermerchantutil.la \
-ltalerexchange \
-ltalerjson \
+ -ltalercurl \
-ltalerutil \
-ltalerpq \
-lgnunetpq \
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
@@ -112,6 +112,7 @@
#include "taler-merchant-httpd_spa.h"
#include "taler-merchant-httpd_statics.h"
#include "taler-merchant-httpd_terms.h"
+#include "taler-merchant-httpd_post-reports-ID.h"
#include "taler-merchant-httpd_private-delete-report-ID.h"
#include "taler-merchant-httpd_private-get-report-ID.h"
#include "taler-merchant-httpd_private-get-reports.h"
@@ -2110,6 +2111,13 @@ url_handler (void *cls,
.have_id_segment = true,
.handler = &TMH_return_static
},
+ /* POST /reports/$ID/ */
+ {
+ .url_prefix = "/reports",
+ .method = MHD_HTTP_METHOD_POST,
+ .have_id_segment = true,
+ .handler = &TMH_post_reports_ID,
+ },
/* GET /templates/$ID/: */
{
.url_prefix = "/templates/",
diff --git a/src/backend/taler-merchant-report-generator.c b/src/backend/taler-merchant-report-generator.c
@@ -23,6 +23,8 @@
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_db_lib.h>
#include <gnunet/gnunet_curl_lib.h>
+#include <taler_merchant_util.h>
+#include <taler/taler_curl_lib.h>
#include <taler/taler_merchantdb_plugin.h>
#include <taler/taler_merchantdb_lib.h>
#include <taler/taler_dbevents.h>
@@ -58,6 +60,11 @@ struct ReportActivity
struct GNUNET_ChildWaitHandle *cwh;
/**
+ * Minor context that holds body and headers.
+ */
+ struct TALER_CURL_PostContext post_ctx;
+
+ /**
* CURL easy handle for the HTTP request.
*/
CURL *eh;
@@ -68,14 +75,14 @@ struct ReportActivity
struct GNUNET_CURL_Job *job;
/**
- * URL of the request.
+ * ID of the instance we are working on.
*/
- char *url;
+ char *instance_id;
/**
- * ID of the instance we are working on.
+ * URL where we request the report from.
*/
- char *instance_id;
+ char *url;
/**
* Report program section.
@@ -192,6 +199,7 @@ free_ra (struct ReportActivity *ra)
GNUNET_OS_process_destroy (ra->proc);
ra->proc = NULL;
}
+ TALER_curl_easy_post_finished (&ra->post_ctx);
if (NULL != ra->eh)
{
curl_easy_cleanup (ra->eh);
@@ -458,21 +466,18 @@ curl_completed_cb (void *cls,
*
* @param[in,out] ra which report activity are we working on
* @param mime_type mime type to request from @a data_source
- * @param data_source relative URL path to request data from
+ * @param report_token token to get access to the report
*/
static void
-fetch_and_transmit (struct ReportActivity *ra,
- const char *mime_type,
- const char *data_source)
+fetch_and_transmit (
+ struct ReportActivity *ra,
+ const char *mime_type,
+ const struct TALER_MERCHANT_ReportToken *report_token)
{
- struct curl_slist *headers = NULL;
- char *accept_header;
-
GNUNET_asprintf (&ra->url,
- "%sinstances/%s%s",
+ "%sreports/%llu",
base_url,
- ra->instance_id,
- data_source);
+ (unsigned long long) ra->report_id);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Fetching report from %s\n",
ra->url);
@@ -487,28 +492,46 @@ fetch_and_transmit (struct ReportActivity *ra,
return;
}
- GNUNET_asprintf (&accept_header,
- "Accept: %s",
- mime_type);
- headers = curl_slist_append (headers,
- accept_header);
- GNUNET_free (accept_header);
+ {
+ char *accept_header;
+
+ GNUNET_asprintf (&accept_header,
+ "Accept: %s",
+ mime_type);
+ ra->post_ctx.headers = curl_slist_append (ra->post_ctx.headers,
+ accept_header);
+ GNUNET_free (accept_header);
+ }
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_URL,
ra->url));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_HTTPHEADER,
- headers));
- // FIXME: need to set Authorization header!!!
+ {
+ json_t *req;
+
+ req = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_data_auto ("report_token",
+ report_token));
+ if (GNUNET_OK !=
+ TALER_curl_easy_post (&ra->post_ctx,
+ ra->eh,
+ req))
+ {
+ GNUNET_break (0);
+ json_decref (req);
+ finish_transmission (ra,
+ TALER_EC_GENERIC_CURL_ALLOCATION_FAILURE,
+ "TALER_curl_easy_post");
+ return;
+ }
+ json_decref (req);
+ }
ra->job = GNUNET_CURL_job_add_raw (curl_ctx,
ra->eh,
- headers,
+ ra->post_ctx.headers,
&curl_completed_cb,
ra);
ra->eh = NULL;
- curl_slist_free_all (headers);
}
@@ -519,25 +542,30 @@ fetch_and_transmit (struct ReportActivity *ra,
* @param instance_id name of the instance
* @param report_id serial number of the report
* @param report_program_section configuration section of program
+ * for report generation
* @param report_description text describing the report
* @param mime_type mime type to request
- * @param data_source relative URL to request report data from
+ * @param report_token token to authorize access to the data source
* @param target_address where to send report data
* @param frequency report frequency
- * @param frequency_shift time shift from frequency multiple
+ * @param frequency_shift how much to shift the report time from a
+ * multiple of the report @a frequency
+ * @param next_transmission when is the next transmission of this report
+ * due
*/
static void
-process_pending_report (void *cls,
- const char *instance_id,
- uint64_t report_id,
- const char *report_program_section,
- const char *report_description,
- const char *mime_type,
- const char *data_source,
- const char *target_address,
- struct GNUNET_TIME_Relative frequency,
- struct GNUNET_TIME_Relative frequency_shift,
- struct GNUNET_TIME_Absolute next_transmission)
+process_pending_report (
+ void *cls,
+ const char *instance_id,
+ uint64_t report_id,
+ const char *report_program_section,
+ const char *report_description,
+ const char *mime_type,
+ const struct TALER_MERCHANT_ReportToken *report_token,
+ const char *target_address,
+ struct GNUNET_TIME_Relative frequency,
+ struct GNUNET_TIME_Relative frequency_shift,
+ struct GNUNET_TIME_Absolute next_transmission)
{
struct GNUNET_TIME_Absolute *next = cls;
struct ReportActivity *ra;
@@ -572,7 +600,7 @@ process_pending_report (void *cls,
ra);
fetch_and_transmit (ra,
mime_type,
- data_source);
+ report_token);
}
diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am
@@ -151,6 +151,7 @@ libtaler_plugin_merchantdb_postgres_la_SOURCES = \
pg_insert_report.h pg_insert_report.c \
pg_delete_report.h pg_delete_report.c \
pg_update_report.h pg_update_report.c \
+ pg_check_report.h pg_check_report.c \
pg_select_reports.h pg_select_reports.c \
pg_lookup_reports_pending.h pg_lookup_reports_pending.c \
pg_update_report_status.h pg_update_report_status.c \
diff --git a/src/backenddb/merchant-0028.sql b/src/backenddb/merchant-0028.sql
@@ -31,6 +31,7 @@ CREATE TABLE merchant_reports
,report_program_section TEXT NOT NULL
,report_description TEXT NOT NULL
,mime_type TEXT NOT NULL
+ ,report_token BYTEA NOT NULL CHECK (LENGTH(report_token)=32)
,data_source TEXT NOT NULL
,target_address TEXT NOT NULL
,frequency INT8 NOT NULL
@@ -49,6 +50,8 @@ COMMENT ON COLUMN merchant_reports.report_program_section
IS 'Which helper program (configuration section) to use to transmit the report';
COMMENT ON COLUMN merchant_reports.mime_type
IS 'Mime-type to request from the backend for the transmission';
+COMMENT ON COLUMN merchant_reports.report_token
+ IS 'Token clients requesting the report must include in the /report request';
COMMENT ON COLUMN merchant_reports.data_source
IS 'Relative URL of the instance for a GET request to request data to send';
COMMENT ON COLUMN merchant_reports.target_address
diff --git a/src/backenddb/pg_check_report.c b/src/backenddb/pg_check_report.c
@@ -0,0 +1,68 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2025 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_check_report.c
+ * @brief Implementation of the check_report function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_check_report.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_check_report (void *cls,
+ uint64_t report_id,
+ const struct TALER_MERCHANT_ReportToken *report_token,
+ const char *mime_type,
+ char **instance_id,
+ char **data_source)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&report_id),
+ GNUNET_PQ_query_param_auto_from_type (report_token),
+ GNUNET_PQ_query_param_string (mime_type),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("instance_id",
+ instance_id),
+ GNUNET_PQ_result_spec_string ("data_source",
+ data_source),
+ GNUNET_PQ_result_spec_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "check_report",
+ "SELECT"
+ " mi.merchant_id"
+ " ,mr.data_source"
+ " FROM merchant_reports mr"
+ " JOIN merchant_instances mi"
+ " USING (merchant_serial)"
+ " WHERE mr.report_serial=$1"
+ " AND mr.report_token=$2"
+ " AND mr.mime_type=$3;");
+ return GNUNET_PQ_eval_prepared_singleton_select (
+ pg->conn,
+ "check_report",
+ params,
+ rs);
+}
diff --git a/src/backenddb/pg_check_report.h b/src/backenddb/pg_check_report.h
@@ -0,0 +1,51 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2025 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_check_report.h
+ * @brief implementation of the check_report function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_CHECK_REPORT_H
+#define PG_CHECK_REPORT_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Check that a particular report is scheduled under the
+ * given @a report_id and @a report_token. Does not
+ * validate that the report is actually due.
+ *
+ * @param cls closure
+ * @param report_id serial number of the report to lookup
+ * @param report_token report token to check
+ * @param mime_type mime type to request from the @a data_source
+ * @param[out] instance_id instance to lookup reports for
+ * @param[out] data_source relative URL (to instance base URL)
+ * to request report data from
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_check_report (void *cls,
+ uint64_t report_id,
+ const struct TALER_MERCHANT_ReportToken *report_token,
+ const char *mime_type,
+ char **instance_id,
+ char **data_source);
+
+#endif
diff --git a/src/backenddb/pg_insert_report.c b/src/backenddb/pg_insert_report.c
@@ -40,12 +40,14 @@ TMH_PG_insert_report (
uint64_t *report_id)
{
struct PostgresClosure *pg = cls;
+ struct TALER_MERCHANT_ReportToken report_token;
struct GNUNET_TIME_Timestamp start;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (instance_id),
GNUNET_PQ_query_param_string (report_program_section),
GNUNET_PQ_query_param_string (report_description),
GNUNET_PQ_query_param_string (mime_type),
+ GNUNET_PQ_query_param_auto_from_type (&report_token),
GNUNET_PQ_query_param_string (data_source),
GNUNET_PQ_query_param_string (target_address),
GNUNET_PQ_query_param_relative_time (&frequency),
@@ -59,6 +61,9 @@ TMH_PG_insert_report (
GNUNET_PQ_result_spec_end
};
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &report_token,
+ sizeof (report_token));
start =
GNUNET_TIME_absolute_to_timestamp (
GNUNET_TIME_absolute_add (
@@ -75,13 +80,14 @@ TMH_PG_insert_report (
",report_program_section"
",report_description"
",mime_type"
+ ",report_token"
",data_source"
",target_address"
",frequency"
",frequency_shift"
",next_transmission)"
" SELECT merchant_serial, $2, $3, $4, $5,"
- " $6, $7, $8, $9, $10, $11, $12"
+ " $6, $7, $8, $9, $10, $11, $12, $13"
" FROM merchant_instances"
" WHERE merchant_id=$1"
" ON CONFLICT DO NOTHING;");
diff --git a/src/backenddb/pg_lookup_reports_pending.c b/src/backenddb/pg_lookup_reports_pending.c
@@ -70,7 +70,7 @@ select_pending_reports_cb (void *cls,
char *report_program_section;
char *report_description;
char *mime_type;
- char *data_source;
+ struct TALER_MERCHANT_ReportToken report_token;
char *target_address;
struct GNUNET_TIME_Relative frequency;
struct GNUNET_TIME_Relative frequency_shift;
@@ -86,8 +86,8 @@ select_pending_reports_cb (void *cls,
&report_description),
GNUNET_PQ_result_spec_string ("mime_type",
&mime_type),
- GNUNET_PQ_result_spec_string ("data_source",
- &data_source),
+ GNUNET_PQ_result_spec_auto_from_type ("report_token",
+ &report_token),
GNUNET_PQ_result_spec_string ("target_address",
&target_address),
GNUNET_PQ_result_spec_relative_time ("frequency",
@@ -114,7 +114,7 @@ select_pending_reports_cb (void *cls,
report_program_section,
report_description,
mime_type,
- data_source,
+ &report_token,
target_address,
frequency,
frequency_shift,
@@ -150,7 +150,7 @@ TMH_PG_lookup_reports_pending (void *cls,
" ,mr.report_program_section"
" ,mr.report_description"
" ,mr.mime_type"
- " ,mr.data_source"
+ " ,mr.report_token"
" ,mr.target_address"
" ,mr.frequency"
" ,mr.frequency_shift"
diff --git a/src/backenddb/pg_select_report.c b/src/backenddb/pg_select_report.c
@@ -80,7 +80,7 @@ TMH_PG_select_report (void *cls,
code = TALER_EC_NONE;
check_connection (pg);
PREPARE (pg,
- "select_reports",
+ "select_report",
"SELECT"
" mr.report_program_section"
" ,mr.report_description"
diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c
@@ -62,6 +62,7 @@
#include "pg_insert_report.h"
#include "pg_delete_report.h"
#include "pg_update_report.h"
+#include "pg_check_report.h"
#include "pg_select_reports.h"
#include "pg_lookup_reports_pending.h"
#include "pg_update_report_status.h"
@@ -694,6 +695,8 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
= &TMH_PG_delete_report;
plugin->update_report
= &TMH_PG_update_report;
+ plugin->check_report
+ = &TMH_PG_check_report;
plugin->select_reports
= &TMH_PG_select_reports;
plugin->lookup_reports_pending
diff --git a/src/include/taler_merchant_util.h b/src/include/taler_merchant_util.h
@@ -188,6 +188,18 @@ struct TALER_MERCHANT_MFA_BodySalt
/**
+ * @brief Token used to authorize report generation.
+ */
+struct TALER_MERCHANT_ReportToken
+{
+ /**
+ * Salt.
+ */
+ uint64_t salt[256 / 64];
+};
+
+
+/**
* Hash the given request @a body with the given @a salt to
* produce @a h_body for MFA checks.
*
diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h
@@ -27,8 +27,8 @@
#include <gnunet/gnunet_time_lib.h>
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_db_lib.h>
-#include <taler/taler_exchange_service.h>
#include <taler_merchant_util.h>
+#include <taler/taler_exchange_service.h>
#include <jansson.h>
#ifdef HAVE_DONAU_DONAU_SERVICE_H
@@ -1372,9 +1372,8 @@ typedef void
* @param report_program_section configuration section of program
* for report generation
* @param report_description text describing the report
- * @param mime_type mime type to request from the @a data_source
- * @param data_source relative URL (to instance base URL)
- * to request report data from
+ * @param mime_type mime type to request
+ * @param report_token token to authorize access to the data source
* @param target_address where to send report data
* @param frequency report frequency
* @param frequency_shift how much to shift the report time from a
@@ -1390,7 +1389,7 @@ typedef void
const char *report_program_section,
const char *report_description,
const char *mime_type,
- const char *data_source,
+ const struct TALER_MERCHANT_ReportToken *report_token,
const char *target_address,
struct GNUNET_TIME_Relative frequency,
struct GNUNET_TIME_Relative frequency_shift,
@@ -5086,6 +5085,29 @@ struct TALER_MERCHANTDB_Plugin
char **last_error_detail);
/**
+ * Check that a particular report is scheduled under the
+ * given @a report_id and @a report_token. Does not
+ * validate that the report is actually due.
+ *
+ * @param cls closure
+ * @param report_id serial number of the report to lookup
+ * @param report_token report token to check
+ * @param mime_type mime type to request from the @a data_source
+ * @param[out] instance_id instance to lookup reports for
+ * @param[out] data_source relative URL (to instance base URL)
+ * to request report data from
+ * @return database result code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*check_report)(void *cls,
+ uint64_t report_id,
+ const struct TALER_MERCHANT_ReportToken *report_token,
+ const char *mime_type,
+ char **instance_id,
+ char **data_source);
+
+
+ /**
* Delete information about a report.
*
* @param cls closure