aboutsummaryrefslogtreecommitdiff
path: root/src/exchange
diff options
context:
space:
mode:
authorÖzgür Kesim <oec-taler@kesim.org>2022-10-02 18:05:58 +0200
committerÖzgür Kesim <oec-taler@kesim.org>2022-10-02 18:05:58 +0200
commit04c7e0bb337dd88dde60293d94d2e192a8fc2ff5 (patch)
treebff69b52b8d07be2442dde6ca86a3df2776b2e67 /src/exchange
parent165b85ddd59ce4af9b3f28409b6210d8f688f17d (diff)
Refactor extensions
- Extensions are now compiled as shared libraries and loaded at runtime according to the TALER configuration. - So far, only age restriction is loaded as extension. - Groundwork for extension auction_brandt started.
Diffstat (limited to 'src/exchange')
-rw-r--r--src/exchange/taler-exchange-httpd.c61
-rw-r--r--src/exchange/taler-exchange-httpd.h9
-rw-r--r--src/exchange/taler-exchange-httpd_extensions.c59
-rw-r--r--src/exchange/taler-exchange-httpd_keys.c74
-rw-r--r--src/exchange/taler-exchange-httpd_management_extensions.c3
-rw-r--r--src/exchange/taler-exchange-httpd_refreshes_reveal.c9
6 files changed, 148 insertions, 67 deletions
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
index 496d3d29..d7651d79 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -98,6 +98,13 @@ static int allow_address_reuse;
const struct GNUNET_CONFIGURATION_Handle *TEH_cfg;
/**
+ * Configuration of age restriction
+ *
+ * Set after loading the library, enabled in database event handler.
+ */
+struct TALER_AgeRestrictionConfig TEH_age_restriction_config = {0};
+
+/**
* Handle to the HTTP server.
*/
static struct MHD_Daemon *mhd;
@@ -139,11 +146,6 @@ char *TEH_currency;
char *TEH_base_url;
/**
- * Age restriction flags and mask
- */
-bool TEH_age_restriction_enabled = true;
-
-/**
* Default timeout in seconds for HTTP requests.
*/
static unsigned int connection_timeout = 30;
@@ -170,6 +172,7 @@ bool TEH_suicide;
* TALER_SIGNATURE_MASTER_EXTENSION.
*/
struct TALER_MasterSignatureP TEH_extensions_sig;
+bool TEH_extensions_signed = false;
/**
* Value to return from main()
@@ -1039,6 +1042,46 @@ handle_post_auditors (struct TEH_RequestContext *rc,
/**
+ * Handle POST "/extensions/..." requests.
+ *
+ * @param rc request context
+ * @param root uploaded JSON data
+ * @param args array of additional options
+ * @return MHD result code
+ */
+static MHD_RESULT
+handle_post_extensions (struct TEH_RequestContext *rc,
+ const json_t *root,
+ const char *const args[])
+{
+ const struct TALER_Extension *ext = NULL;
+
+ if (NULL == args[0])
+ {
+ GNUNET_break_op (0);
+ return r404 (rc->connection,
+ "/extensions/$EXTENSION");
+ }
+
+ ext = TALER_extensions_get_by_name (args[0]);
+ if (NULL == ext)
+ {
+ GNUNET_break_op (0);
+ return r404 (rc->connection,
+ "/extensions/$EXTENSION unknown");
+ }
+
+ if (NULL == ext->http_post_handler)
+ return MHD_HTTP_NOT_IMPLEMENTED;
+
+ return ext->http_post_handler (
+ rc->connection,
+ root,
+ &args[1]);
+}
+
+
+/**
* Handle incoming HTTP request.
*
* @param cls closure for MHD daemon (unused)
@@ -1255,6 +1298,14 @@ handle_mhd_request (void *cls,
.nargs = 4,
.nargs_is_upper_bound = true
},
+ /* extensions endpoints */
+ {
+ .url = "extensions",
+ .method = MHD_HTTP_METHOD_POST,
+ .handler.post = &handle_post_extensions,
+ .nargs = 4, /* Arbitrary upper bound */
+ .nargs_is_upper_bound = true,
+ },
/* mark end of list */
{
.url = NULL
diff --git a/src/exchange/taler-exchange-httpd.h b/src/exchange/taler-exchange-httpd.h
index 0fda5ed8..77aab249 100644
--- a/src/exchange/taler-exchange-httpd.h
+++ b/src/exchange/taler-exchange-httpd.h
@@ -197,11 +197,6 @@ extern struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
*/
extern char *TEH_currency;
-/*
- * Age restriction extension state
- */
-extern bool TEH_age_restriction_enabled;
-
/**
* Our (externally visible) base URL.
*/
@@ -221,6 +216,7 @@ extern struct GNUNET_CURL_Context *TEH_curl_ctx;
* Signature of the offline master key of all enabled extensions' configuration
*/
extern struct TALER_MasterSignatureP TEH_extensions_sig;
+extern bool TEH_extensions_signed;
/**
* @brief Struct describing an URL and the handler for it.
@@ -366,4 +362,7 @@ struct TEH_RequestHandler
};
+/* Age restriction configuration */
+extern struct TALER_AgeRestrictionConfig TEH_age_restriction_config;
+
#endif
diff --git a/src/exchange/taler-exchange-httpd_extensions.c b/src/exchange/taler-exchange-httpd_extensions.c
index d6c26f6f..2a99d7a2 100644
--- a/src/exchange/taler-exchange-httpd_extensions.c
+++ b/src/exchange/taler-exchange-httpd_extensions.c
@@ -100,6 +100,9 @@ extension_update_event_cb (void *cls,
// No config found -> disable extension
if (NULL == config_str)
{
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "No configuration found for extension %s, disabling it\n",
+ extension->name);
extension->disable ((struct TALER_Extension *) extension);
return;
}
@@ -114,28 +117,40 @@ extension_update_event_cb (void *cls,
err.text,
err.source);
GNUNET_break (0);
+ free(config_str);
return;
}
// Call the parser for the extension
ret = extension->load_json_config (
(struct TALER_Extension *) extension,
- config);
+ json_object_get(config, "config"));
if (GNUNET_OK != ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Couldn't parse configuration for extension %s from the database",
- extension->name);
+ "Couldn't parse configuration for extension %s from the database: %s\n",
+ extension->name,
+ config_str);
GNUNET_break (0);
}
+
+ free(config_str);
+ json_decref(config);
}
/* Special case age restriction: Update global flag and mask */
if (TALER_Extension_AgeRestriction == type)
{
- TEH_age_restriction_enabled =
- TALER_extensions_age_restriction_is_enabled ();
+ const struct TALER_AgeRestrictionConfig *conf =
+ TALER_extensions_get_age_restriction_config ();
+ if (NULL != conf)
+ TEH_age_restriction_config = *conf;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "[age restriction] DB event has changed the config to %s with mask: %s\n",
+ conf->enabled ? "enabled": "disabled",
+ TALER_age_mask_to_string (&conf->mask));
+
}
}
@@ -143,14 +158,21 @@ extension_update_event_cb (void *cls,
enum GNUNET_GenericReturnValue
TEH_extensions_init ()
{
- GNUNET_assert (GNUNET_OK ==
- TALER_extension_age_restriction_register ());
-
/* Set the event handler for updates */
struct GNUNET_DB_EventHeaderP ev = {
.size = htons (sizeof (ev)),
.type = htons (TALER_DBEVENT_EXCHANGE_EXTENSIONS_UPDATED),
};
+
+ /* Load the shared libraries first */
+ if (GNUNET_OK !=
+ TALER_extensions_load (TEH_cfg))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "failed to load extensions");
+ return GNUNET_SYSERR;
+ }
+
extensions_eh = TEH_plugin->event_listen (TEH_plugin->cls,
GNUNET_TIME_UNIT_FOREVER_REL,
&ev,
@@ -162,17 +184,20 @@ TEH_extensions_init ()
return GNUNET_SYSERR;
}
- /* FIXME #7270: shall we load the extensions from the config right away?
- * We do have to for now, as otherwise denominations with age restriction
- * will not have the age mask set right upon initial generation.
- */
- TALER_extensions_load_taler_config (TEH_cfg);
-
/* Trigger the initial load of configuration from the db */
- for (const struct TALER_Extension *it = TALER_extensions_get_head ();
- NULL != it->next;
+ for (const struct TALER_Extensions *it = TALER_extensions_get_head ();
+ NULL != it && NULL != it->extension;
it = it->next)
- extension_update_event_cb (NULL, &it->type, sizeof(it->type));
+ {
+ const struct TALER_Extension *ext = it->extension;
+ char *conf = json_dumps (ext->config_to_json (ext), JSON_COMPACT);
+
+ TEH_plugin->set_extension_config (TEH_plugin->cls,
+ ext->name,
+ conf);
+ extension_update_event_cb (NULL, &ext->type, sizeof(ext->type));
+ free (conf);
+ }
return GNUNET_OK;
}
diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c
index a6ad9976..4fb8a717 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -815,10 +815,7 @@ static struct TALER_AgeMask
load_age_mask (const char*section_name)
{
static const struct TALER_AgeMask null_mask = {0};
- struct TALER_AgeMask age_mask = TALER_extensions_age_restriction_ageMask ();
-
- if (age_mask.bits == 0)
- return null_mask;
+ enum GNUNET_GenericReturnValue ret;
if (GNUNET_OK != (GNUNET_CONFIGURATION_have_value (
TEH_cfg,
@@ -826,22 +823,29 @@ load_age_mask (const char*section_name)
"AGE_RESTRICTED")))
return null_mask;
+ if (GNUNET_SYSERR ==
+ (ret = GNUNET_CONFIGURATION_get_value_yesno (TEH_cfg,
+ section_name,
+ "AGE_RESTRICTED")))
{
- enum GNUNET_GenericReturnValue ret;
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ section_name,
+ "AGE_RESTRICTED",
+ "Value must be YES or NO\n");
+ return null_mask;
+ }
- if (GNUNET_SYSERR ==
- (ret = GNUNET_CONFIGURATION_get_value_yesno (TEH_cfg,
- section_name,
- "AGE_RESTRICTED")))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- section_name,
- "AGE_RESTRICTED",
- "Value must be YES or NO\n");
- return null_mask;
- }
+ if (GNUNET_OK == ret)
+ {
+ if (! TEH_age_restriction_config.enabled)
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "age restriction set in section %s, yet, age restriction is not enabled\n",
+ section_name);
+ return TEH_age_restriction_config.mask;
}
- return age_mask;
+
+
+ return null_mask;
}
@@ -1898,34 +1902,29 @@ create_krd (struct TEH_KeyStateHandle *ksh,
bool has_extensions = false;
/* Fill in the configurations of the enabled extensions */
- for (const struct TALER_Extension *extension = TALER_extensions_get_head ();
- NULL != extension;
- extension = extension->next)
+ for (const struct TALER_Extensions *iter = TALER_extensions_get_head ();
+ NULL != iter && NULL != iter->extension;
+ iter = iter->next)
{
+ const struct TALER_Extension *extension = iter->extension;
json_t *ext;
- json_t *config_json;
int r;
- /* skip if not configured == disabled */
- if (NULL == extension->config ||
- NULL == extension->config_json)
+ /* skip if not enabled */
+ if (! extension->enabled)
continue;
/* flag our findings so far */
has_extensions = true;
-
GNUNET_assert (NULL != extension->config_json);
- config_json = json_copy (extension->config_json);
- GNUNET_assert (NULL != config_json);
-
ext = GNUNET_JSON_PACK (
GNUNET_JSON_pack_bool ("critical",
extension->critical),
GNUNET_JSON_pack_string ("version",
extension->version),
- GNUNET_JSON_pack_object_steal ("config",
- config_json)
+ GNUNET_JSON_pack_object_incref ("config",
+ extension->config_json)
);
GNUNET_assert (NULL != ext);
@@ -1948,12 +1947,16 @@ create_krd (struct TEH_KeyStateHandle *ksh,
extensions);
GNUNET_assert (0 == r);
- sig = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_data_auto ("extensions_sig",
- &TEH_extensions_sig));
+ /* Add the signature of the extensions, if it is not zero */
+ if (TEH_extensions_signed)
+ {
+ sig = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_data_auto ("extensions_sig",
+ &TEH_extensions_sig));
- r = json_object_update (keys, sig);
- GNUNET_assert (0 == r);
+ r = json_object_update (keys, sig);
+ GNUNET_assert (0 == r);
+ }
}
else
{
@@ -2560,6 +2563,7 @@ build_key_state (struct HelperState *hs,
true);
return NULL;
}
+
/* NOTE: ONLY fetches non-revoked AND master-signed signkeys! */
qs = TEH_plugin->iterate_active_signkeys (TEH_plugin->cls,
&signkey_info_cb,
diff --git a/src/exchange/taler-exchange-httpd_management_extensions.c b/src/exchange/taler-exchange-httpd_management_extensions.c
index a663b1b0..c70ad25e 100644
--- a/src/exchange/taler-exchange-httpd_management_extensions.c
+++ b/src/exchange/taler-exchange-httpd_management_extensions.c
@@ -108,6 +108,8 @@ set_extensions (void *cls,
taler_ext->name,
config);
+ free (config);
+
if (qs < 0)
{
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
@@ -137,6 +139,7 @@ set_extensions (void *cls,
/* All extensions configured, update the signature */
TEH_extensions_sig = sec->extensions_sig;
+ TEH_extensions_signed = true;
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; /* only 'success', so >=0, matters here */
}
diff --git a/src/exchange/taler-exchange-httpd_refreshes_reveal.c b/src/exchange/taler-exchange-httpd_refreshes_reveal.c
index a25d6ff4..09ab572b 100644
--- a/src/exchange/taler-exchange-httpd_refreshes_reveal.c
+++ b/src/exchange/taler-exchange-httpd_refreshes_reveal.c
@@ -603,7 +603,7 @@ resolve_refreshes_reveal_denominations (
&rrc->coin_envelope_hash);
}
- if (TEH_age_restriction_enabled &&
+ if (TEH_age_restriction_config.enabled &&
((NULL == old_age_commitment_json) !=
TALER_AgeCommitmentHash_isNullOrZero (
&rctx->melt.session.coin.h_age_commitment)))
@@ -614,7 +614,7 @@ resolve_refreshes_reveal_denominations (
/* Reconstruct the old age commitment and verify its hash matches the one
* from the melt request */
- if (TEH_age_restriction_enabled &&
+ if (TEH_age_restriction_config.enabled &&
(NULL != old_age_commitment_json))
{
enum GNUNET_GenericReturnValue res;
@@ -623,8 +623,7 @@ resolve_refreshes_reveal_denominations (
bool failed = true;
/* Has been checked in handle_refreshes_reveal_json() */
- GNUNET_assert (ng ==
- TALER_extensions_age_restriction_num_groups ());
+ GNUNET_assert (ng == TEH_age_restriction_config.num_groups);
rctx->old_age_commitment = GNUNET_new (struct TALER_AgeCommitment);
oac = rctx->old_age_commitment;
@@ -931,7 +930,7 @@ handle_refreshes_reveal_json (struct MHD_Connection *connection,
/* Sanity check of age commitment: If it was provided, it _must_ be an array
* of the size the # of age groups */
if (NULL != old_age_commitment_json
- && TALER_extensions_age_restriction_num_groups () !=
+ && TEH_age_restriction_config.num_groups !=
json_array_size (old_age_commitment_json))
{
GNUNET_break_op (0);