commit a7eac286d3e87097c16c5189b4518c64113f4867
parent ddbc213487a90dd1285c454b780fbdb3da5bb2a7
Author: bohdan-potuzhnyi <bohdan.potuzhnyi@gmail.com>
Date: Wed, 6 Aug 2025 14:04:56 +0200
Merge branch 'master' into dev/bohdan-potuzhnyi/donau-integration
Diffstat:
10 files changed, 155 insertions(+), 39 deletions(-)
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
@@ -110,11 +110,6 @@
#endif
/**
- * Fixme: document.
- */
-#define INSTANCE_STALENESS GNUNET_TIME_UNIT_MINUTES
-
-/**
* Backlog for listen operation on unix-domain sockets.
*/
#define UNIX_BACKLOG 500
@@ -1961,6 +1956,19 @@ url_handler (void *cls,
.handler = &TMH_post_using_templates_ID,
.max_upload = 1024 * 1024
},
+ /* POST /instances */
+ {
+ .url_prefix = "/instances",
+ .method = MHD_HTTP_METHOD_POST,
+ .skip_instance = true,
+ .default_only = true,
+ .handler = &TMH_public_post_instances,
+ /* allow instance data of up to 8 MB, that should be plenty;
+ note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
+ would require further changes to the allocation logic
+ in the code... */
+ .max_upload = 1024 * 1024 * 8
+ },
{
.url_prefix = "*",
.method = MHD_HTTP_METHOD_OPTIONS,
diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2023 Taler Systems SA
+ Copyright (C) 2014-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
@@ -182,6 +182,12 @@ struct TMH_MerchantInstance
* against the DB value when updating the auth token.
*/
bool auth_override;
+
+ /**
+ * True if email/sms validation is needed before the
+ * instance can be used.
+ */
+ bool validation_needed;
};
@@ -770,7 +776,7 @@ extern int TMH_strict_v19;
extern int TMH_auth_disabled;
/**
- * True if self-provisioning is enabled.
+ * #GNUNET_YES if self-provisioning is enabled.
*/
extern int TMH_have_self_provisioning;
diff --git a/src/backend/taler-merchant-httpd_private-post-instances.c b/src/backend/taler-merchant-httpd_private-post-instances.c
@@ -25,6 +25,7 @@
#include "platform.h"
#include "taler-merchant-httpd_private-post-instances.h"
#include "taler-merchant-httpd_helper.h"
+#include "taler-merchant-httpd.h"
#include "taler_merchant_bank_lib.h"
#include <taler/taler_dbevents.h>
#include <taler/taler_json_lib.h>
@@ -42,12 +43,16 @@
* @param rh context of the handler
* @param connection the MHD connection to handle
* @param[in,out] hc context with further information about the request
+ * @param validation_needed true if self-provisioned and
+ * email/phone registration is required before the
+ * instance can become fully active
* @return MHD result code
*/
MHD_RESULT
-TMH_private_post_instances (const struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- struct TMH_HandlerContext *hc)
+post_instances (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc,
+ bool validation_needed)
{
struct TALER_MERCHANTDB_InstanceSettings is = { 0 };
struct TALER_MERCHANTDB_InstanceAuthSettings ias;
@@ -282,6 +287,7 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
if (NULL != is.logo)
mi->settings.logo = GNUNET_strdup (is.logo);
mi->auth = ias;
+ mi->validation_needed = validation_needed;
GNUNET_CRYPTO_eddsa_key_create (&mi->merchant_priv.eddsa_priv);
GNUNET_CRYPTO_eddsa_key_get_public (&mi->merchant_priv.eddsa_priv,
&mi->merchant_pub.eddsa_pub);
@@ -304,7 +310,8 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
&mi->merchant_pub,
&mi->merchant_priv,
&mi->settings,
- &mi->auth);
+ &mi->auth,
+ validation_needed);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
@@ -374,4 +381,55 @@ retry:
}
+/**
+ * Generate an instance, given its configuration.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] hc context with further information about the request
+ * @return MHD result code
+ */
+MHD_RESULT
+TMH_private_post_instances (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ return post_instances (rh,
+ connection,
+ hc,
+ false);
+}
+
+
+/**
+ * Generate an instance, given its configuration.
+ * Public handler to be used when self-provisioning.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] hc context with further information about the request
+ * @return MHD result code
+ */
+MHD_RESULT
+TMH_public_post_instances (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ if (GNUNET_YES !=
+ TMH_have_self_provisioning)
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_FORBIDDEN,
+ TALER_EC_MERCHANT_GENERIC_UNAUTHORIZED,
+ "Self-provisioning is not enabled");
+ }
+ return post_instances (rh,
+ connection,
+ hc,
+ TEH_TCS_NONE !=
+ TEH_mandatory_tan_channels);
+}
+
+
/* end of taler-merchant-httpd_private-post-instances.c */
diff --git a/src/backend/taler-merchant-httpd_private-post-instances.h b/src/backend/taler-merchant-httpd_private-post-instances.h
@@ -40,4 +40,20 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
struct MHD_Connection *connection,
struct TMH_HandlerContext *hc);
+
+/**
+ * Generate an instance, given its configuration.
+ * Public handler to be used when self-provisioning.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] hc context with further information about the request
+ * @return MHD result code
+ */
+MHD_RESULT
+TMH_public_post_instances (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc);
+
+
#endif
diff --git a/src/backenddb/merchant-0022.sql b/src/backenddb/merchant-0022.sql
@@ -28,8 +28,10 @@ SET search_path TO merchant;
ALTER TABLE merchant_instances
ADD COLUMN phone_number TEXT DEFAULT NULL,
- ADD COLUMN phone_validated BOOL DEFAULT FALSE,
- ADD COLUMN email_validated BOOL DEFAULT FALSE,
+ ADD COLUMN phone_validated BOOL NOT NULL DEFAULT FALSE,
+ ADD COLUMN email_validated BOOL NOT NULL DEFAULT FALSE,
+ ADD COLUMN validation_needed BOOL NOT NULL DEFAULT FALSE,
+ ADD COLUMN validation_expiration INT8 NOT NULL DEFAULT 0,
DROP COLUMN user_type;
COMMENT ON COLUMN merchant_instances.phone_number
@@ -38,5 +40,14 @@ COMMENT ON COLUMN merchant_instances.phone_validated
IS 'TRUE if the merchant backend validated the phone number';
COMMENT ON COLUMN merchant_instances.email_validated
IS 'TRUE if the merchant backend validated the e-mail address';
+COMMENT ON COLUMN merchant_instances.validation_needed
+ IS 'TRUE if this is a self-provisioned instance that still needs the recovery addresses to be validated';
+COMMENT ON COLUMN merchant_instances.validation_expiration
+ IS 'Time when the instance should be garbage collected if the recovery addresses remain unvalidated';
+
+CREATE INDEX merchant_instances_validation_expiration_gc
+ ON merchant_instances
+ (validation_expiration ASC)
+ WHERE validation_needed;
COMMIT;
diff --git a/src/backenddb/pg_insert_instance.c b/src/backenddb/pg_insert_instance.c
@@ -32,7 +32,8 @@ TMH_PG_insert_instance (
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_MerchantPrivateKeyP *merchant_priv,
const struct TALER_MERCHANTDB_InstanceSettings *is,
- const struct TALER_MERCHANTDB_InstanceAuthSettings *ias)
+ const struct TALER_MERCHANTDB_InstanceAuthSettings *ias,
+ bool validation_needed)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -59,6 +60,7 @@ TMH_PG_insert_instance (
(NULL == is->phone)
? GNUNET_PQ_query_param_null ()
: GNUNET_PQ_query_param_string (is->phone),
+ GNUNET_PQ_query_param_bool (validation_needed),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_QueryParam params_priv[] = {
@@ -85,9 +87,11 @@ TMH_PG_insert_instance (
",website"
",email"
",logo"
- ",phone_number)"
+ ",phone_number"
+ ",validation_needed)"
"VALUES"
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)");
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)")
+ ;
qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_instance",
params);
diff --git a/src/backenddb/pg_insert_instance.h b/src/backenddb/pg_insert_instance.h
@@ -33,14 +33,17 @@
* @param merchant_priv private key of the instance
* @param is details about the instance
* @param ias authentication settings for the instance
+ * @param validation_needed true if validation is
+ * required before the instance can be used
* @return database result code
*/
enum GNUNET_DB_QueryStatus
-TMH_PG_insert_instance (void *cls,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct TALER_MerchantPrivateKeyP *merchant_priv,
- const struct TALER_MERCHANTDB_InstanceSettings *is,
- const struct
- TALER_MERCHANTDB_InstanceAuthSettings *ias);
+TMH_PG_insert_instance (
+ void *cls,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct TALER_MerchantPrivateKeyP *merchant_priv,
+ const struct TALER_MERCHANTDB_InstanceSettings *is,
+ const struct TALER_MERCHANTDB_InstanceAuthSettings *ias,
+ bool validation_needed);
#endif
diff --git a/src/backenddb/procedures.sql.in b/src/backenddb/procedures.sql.in
@@ -32,6 +32,11 @@ CREATE PROCEDURE merchant_do_gc()
LANGUAGE plpgsql
AS $$
BEGIN
+ DELETE FROM merchant_instances
+ WHERE validation_needed
+ AND validation_expiration / 1000 / 1000 <
+ EXTRACT(EPOCH FROM now()
+ AT TIME ZONE 'UTC')::bigint;
CALL merchant_statistic_amount_gc ();
CALL merchant_statistic_bucket_gc ();
CALL merchant_statistic_counter_gc ();
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
@@ -44,28 +44,28 @@ static struct TALER_MERCHANTDB_Plugin *plugin;
* @param test 0 on success, non-zero on failure
*/
#define TEST_WITH_FAIL_CLAUSE(test, on_fail) \
- if ((test)) \
- { \
- GNUNET_break (0); \
- on_fail \
- }
+ if ((test)) \
+ { \
+ GNUNET_break (0); \
+ on_fail \
+ }
#define TEST_COND_RET_ON_FAIL(cond, msg) \
- if (! (cond)) \
- { \
- GNUNET_break (0); \
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \
- msg); \
- return 1; \
- }
+ if (! (cond)) \
+ { \
+ GNUNET_break (0); \
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \
+ msg); \
+ return 1; \
+ }
/**
* @param __test 0 on success, non-zero on failure
*/
#define TEST_RET_ON_FAIL(__test) \
- TEST_WITH_FAIL_CLAUSE (__test, \
- return 1; \
- )
+ TEST_WITH_FAIL_CLAUSE (__test, \
+ return 1; \
+ )
/* ********** Instances ********** */
@@ -316,7 +316,8 @@ test_insert_instance (const struct InstanceData *instance,
&instance->merchant_pub,
&instance->merchant_priv,
&instance->instance,
- &ias),
+ &ias,
+ false),
"Insert instance failed\n");
return 0;
}
diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h
@@ -1710,6 +1710,8 @@ struct TALER_MERCHANTDB_Plugin
* @param merchant_pub public key of the instance
* @param merchant_priv private key of the instance
* @param is details about the instance
+ * @param validation_needed true if validation is
+ * required before the instance can be used
* @return database result code
*/
enum GNUNET_DB_QueryStatus
@@ -1717,7 +1719,9 @@ struct TALER_MERCHANTDB_Plugin
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_MerchantPrivateKeyP *merchant_priv,
const struct TALER_MERCHANTDB_InstanceSettings *is,
- const struct TALER_MERCHANTDB_InstanceAuthSettings *ias);
+ const struct TALER_MERCHANTDB_InstanceAuthSettings *ias,
+ bool validation_needed);
+
/**
* Insert information about an instance's account into our database.