aboutsummaryrefslogtreecommitdiff
path: root/src/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'src/extensions')
-rw-r--r--src/extensions/Makefile.am5
-rw-r--r--src/extensions/age_restriction/Makefile.am33
-rw-r--r--src/extensions/age_restriction/age_restriction.c258
-rw-r--r--src/extensions/age_restriction_helper.c73
-rw-r--r--src/extensions/extension_age_restriction.c409
-rw-r--r--src/extensions/extensions.c205
-rw-r--r--src/extensions/policy_brandt_vickrey_auction/Makefile.am34
-rw-r--r--src/extensions/policy_brandt_vickrey_auction/policy_brandt_vickrey_auction.c760
8 files changed, 1298 insertions, 479 deletions
diff --git a/src/extensions/Makefile.am b/src/extensions/Makefile.am
index 5d4ed128..c867a951 100644
--- a/src/extensions/Makefile.am
+++ b/src/extensions/Makefile.am
@@ -11,7 +11,7 @@ if USE_COVERAGE
endif
-# Libraries
+# Basic extension handling library
lib_LTLIBRARIES = \
libtalerextensions.la
@@ -22,7 +22,7 @@ libtalerextensions_la_LDFLAGS = \
libtalerextensions_la_SOURCES = \
extensions.c \
- extension_age_restriction.c
+ age_restriction_helper.c
libtalerextensions_la_LIBADD = \
$(top_builddir)/src/json/libtalerjson.la \
@@ -31,3 +31,4 @@ libtalerextensions_la_LIBADD = \
-lgnunetutil \
-ljansson \
$(XLIB)
+
diff --git a/src/extensions/age_restriction/Makefile.am b/src/extensions/age_restriction/Makefile.am
new file mode 100644
index 00000000..85d67653
--- /dev/null
+++ b/src/extensions/age_restriction/Makefile.am
@@ -0,0 +1,33 @@
+# This Makefile.am is in the public domain
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/include \
+ $(LIBGCRYPT_CFLAGS) \
+ $(POSTGRESQL_CPPFLAGS)
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIB = -lgcov
+endif
+
+# Age restriction as extension library
+
+plugindir = $(libdir)/taler
+
+plugin_LTLIBRARIES = \
+ libtaler_extension_age_restriction.la
+
+libtaler_extension_age_restriction_la_LDFLAGS = \
+ -version-info 0:0:0 \
+ -no-undefined
+
+libtaler_extension_age_restriction_la_SOURCES = \
+ age_restriction.c
+
+libtaler_extension_age_restriction_la_LIBADD = \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetjson \
+ -lgnunetutil \
+ -ljansson \
+ $(XLIB)
diff --git a/src/extensions/age_restriction/age_restriction.c b/src/extensions/age_restriction/age_restriction.c
new file mode 100644
index 00000000..576a6039
--- /dev/null
+++ b/src/extensions/age_restriction/age_restriction.c
@@ -0,0 +1,258 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2021-2022 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 age_restriction.c
+ * @brief Utility functions regarding age restriction
+ * @author Özgür Kesim
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_extensions.h"
+#include "stdint.h"
+
+/* ==================================================
+ *
+ * Age Restriction TALER_Extension implementation
+ *
+ * ==================================================
+ */
+
+/**
+ * @brief local configuration
+ */
+
+static struct TALER_AgeRestrictionConfig AR_config = {0};
+
+/**
+ * @brief implements the TALER_Extension.disable interface.
+ *
+ * @param ext Pointer to the current extension
+ */
+static void
+age_restriction_disable (
+ struct TALER_Extension *ext)
+{
+ if (NULL == ext)
+ return;
+
+ ext->enabled = false;
+ ext->config = NULL;
+
+ AR_config.mask.bits = 0;
+ AR_config.num_groups = 0;
+}
+
+
+/**
+ * @brief implements the TALER_Extension.load_config interface.
+ *
+ * @param ext if NULL, only tests the configuration
+ * @param jconfig the configuration as json
+ */
+static enum GNUNET_GenericReturnValue
+age_restriction_load_config (
+ struct TALER_Extension *ext,
+ json_t *jconfig)
+{
+ struct TALER_AgeMask mask = {0};
+ enum GNUNET_GenericReturnValue ret;
+
+ ret = TALER_JSON_parse_age_groups (jconfig, &mask);
+ if (GNUNET_OK != ret)
+ return ret;
+
+ /* only testing the parser */
+ if (ext == NULL)
+ return GNUNET_OK;
+
+ if (TALER_Extension_AgeRestriction != ext->type)
+ return GNUNET_SYSERR;
+
+ if (mask.bits > 0)
+ {
+ /* if the mask is not zero, the first bit MUST be set */
+ if (0 == (mask.bits & 1))
+ return GNUNET_SYSERR;
+
+ AR_config.mask.bits = mask.bits;
+ AR_config.num_groups = __builtin_popcount (mask.bits) - 1;
+ }
+
+ ext->config = &AR_config;
+ ext->enabled = true;
+ json_decref (jconfig);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "loaded new age restriction config with age groups: %s\n",
+ TALER_age_mask_to_string (&mask));
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * @brief implements the TALER_Extension.manifest interface.
+ *
+ * @param ext if NULL, only tests the configuration
+ * @return configuration as json_t* object, maybe NULL
+ */
+static json_t *
+age_restriction_manifest (
+ const struct TALER_Extension *ext)
+{
+ char *mask_str;
+ json_t *conf;
+
+ GNUNET_assert (NULL != ext);
+
+ if (NULL == ext->config)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "age restriction not configured");
+ return json_null ();
+ }
+
+ mask_str = TALER_age_mask_to_string (&AR_config.mask);
+ conf = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("age_groups", mask_str)
+ );
+
+ free (mask_str);
+
+ return GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_bool ("critical", ext->critical),
+ GNUNET_JSON_pack_string ("version", ext->version),
+ GNUNET_JSON_pack_object_steal ("config", conf)
+ );
+}
+
+
+/* The extension for age restriction */
+struct TALER_Extension TE_age_restriction = {
+ .type = TALER_Extension_AgeRestriction,
+ .name = "age_restriction",
+ .critical = false,
+ .version = "1",
+ .enabled = false, /* disabled per default */
+ .config = NULL,
+ .disable = &age_restriction_disable,
+ .load_config = &age_restriction_load_config,
+ .manifest = &age_restriction_manifest,
+
+ /* This extension is not a policy extension */
+ .parse_policy_details = NULL,
+ .http_get_handler = NULL,
+ .http_post_handler = NULL,
+};
+
+
+/**
+ * @brief implements the init() function for GNUNET_PLUGIN_load
+ *
+ * @param arg Pointer to the GNUNET_CONFIGURATION_Handle
+ * @return pointer to TALER_Extension on success or NULL otherwise.
+ */
+void *
+libtaler_extension_age_restriction_init (void *arg)
+{
+ const struct GNUNET_CONFIGURATION_Handle *cfg = arg;
+ char *groups = NULL;
+ struct TALER_AgeMask mask = {0};
+
+ if ((GNUNET_YES !=
+ GNUNET_CONFIGURATION_have_value (cfg,
+ TALER_EXTENSION_SECTION_AGE_RESTRICTION,
+ "ENABLED"))
+ ||
+ (GNUNET_YES !=
+ GNUNET_CONFIGURATION_get_value_yesno (cfg,
+ TALER_EXTENSION_SECTION_AGE_RESTRICTION,
+ "ENABLED")))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "[age restriction] no section %s found in configuration\n",
+ TALER_EXTENSION_SECTION_AGE_RESTRICTION);
+
+ return NULL;
+ }
+
+ /* Age restriction is enabled, extract age groups */
+ if ((GNUNET_YES ==
+ GNUNET_CONFIGURATION_have_value (cfg,
+ TALER_EXTENSION_SECTION_AGE_RESTRICTION,
+ "AGE_GROUPS"))
+ &&
+ (GNUNET_YES !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ TALER_EXTENSION_SECTION_AGE_RESTRICTION,
+ "AGE_GROUPS",
+ &groups)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "[age restriction] AGE_GROUPS in %s is not a string\n",
+ TALER_EXTENSION_SECTION_AGE_RESTRICTION);
+
+ return NULL;
+ }
+
+ mask.bits = TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK;
+
+ if ((groups != NULL) &&
+ (GNUNET_OK != TALER_parse_age_group_string (groups, &mask)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "[age restriction] couldn't parse age groups: '%s'\n",
+ groups);
+ return NULL;
+ }
+
+ AR_config.mask = mask;
+ AR_config.num_groups = __builtin_popcount (mask.bits) - 1; /* no underflow, first bit always set */
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "[age restriction] setting age mask to %s with #groups: %d\n",
+ TALER_age_mask_to_string (&AR_config.mask),
+ __builtin_popcount (AR_config.mask.bits) - 1);
+
+ TE_age_restriction.config = &AR_config;
+
+ /* Note: we do now have TE_age_restriction_config set, however the extension
+ * is not yet enabled! For age restriction to become active, load_config must
+ * have been called. */
+
+ GNUNET_free (groups);
+ return &TE_age_restriction;
+}
+
+
+/**
+ * @brief implements the done() function for GNUNET_PLUGIN_load
+ *
+ * @param cfg unsued
+ * @return pointer to TALER_Extension on success or NULL otherwise.
+ */
+void *
+libtaler_extension_age_restriction_done (void *arg)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "[age restriction] disabling and unloading");
+ AR_config.mask.bits = 0;
+ AR_config.num_groups = 0;
+ return NULL;
+}
+
+
+/* end of age_restriction.c */
diff --git a/src/extensions/age_restriction_helper.c b/src/extensions/age_restriction_helper.c
new file mode 100644
index 00000000..8ba83511
--- /dev/null
+++ b/src/extensions/age_restriction_helper.c
@@ -0,0 +1,73 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022- 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 age_restriction_helper.c
+ * @brief Helper functions for age restriction
+ * @author Özgür Kesim
+ */
+
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_extensions.h"
+#include "stdint.h"
+
+
+const struct TALER_AgeRestrictionConfig *
+TALER_extensions_get_age_restriction_config ()
+{
+ const struct TALER_Extension *ext;
+
+ ext = TALER_extensions_get_by_type (TALER_Extension_AgeRestriction);
+ if (NULL == ext)
+ return NULL;
+
+ return ext->config;
+}
+
+
+bool
+TALER_extensions_is_age_restriction_enabled ()
+{
+ const struct TALER_Extension *ext;
+
+ ext = TALER_extensions_get_by_type (TALER_Extension_AgeRestriction);
+ if (NULL == ext)
+ return false;
+
+ return ext->enabled;
+}
+
+
+struct TALER_AgeMask
+TALER_extensions_get_age_restriction_mask ()
+{
+ const struct TALER_Extension *ext;
+ const struct TALER_AgeRestrictionConfig *conf;
+
+ ext = TALER_extensions_get_by_type (TALER_Extension_AgeRestriction);
+
+ if ((NULL == ext) ||
+ (NULL == ext->config))
+ return (struct TALER_AgeMask) {0}
+ ;
+
+ conf = ext->config;
+ return conf->mask;
+}
+
+
+/* end age_restriction_helper.c */
diff --git a/src/extensions/extension_age_restriction.c b/src/extensions/extension_age_restriction.c
deleted file mode 100644
index 00a03841..00000000
--- a/src/extensions/extension_age_restriction.c
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2021-2022 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 extension_age_restriction.c
- * @brief Utility functions regarding age restriction
- * @author Özgür Kesim
- */
-#include "platform.h"
-#include "taler_util.h"
-#include "taler_extensions.h"
-#include "stdint.h"
-
-/**
- * Carries all the information we need for age restriction
- */
-struct age_restriction_config
-{
- struct TALER_AgeMask mask;
- size_t num_groups;
-};
-
-/**
- * Global config for this extension
- */
-static struct age_restriction_config TE_age_restriction_config = {0};
-
-enum GNUNET_GenericReturnValue
-TALER_parse_age_group_string (
- const char *groups,
- struct TALER_AgeMask *mask)
-{
-
- const char *pos = groups;
- unsigned int prev = 0;
- unsigned int val = 0;
- char c;
-
- while (*pos)
- {
- c = *pos++;
- if (':' == c)
- {
- if (prev >= val)
- return GNUNET_SYSERR;
-
- mask->bits |= 1 << val;
- prev = val;
- val = 0;
- continue;
- }
-
- if ('0'>c || '9'<c)
- return GNUNET_SYSERR;
-
- val = 10 * val + c - '0';
-
- if (0>=val || 32<=val)
- return GNUNET_SYSERR;
- }
-
- if (32<=val || prev>=val)
- return GNUNET_SYSERR;
-
- mask->bits |= (1 << val);
- mask->bits |= 1; // mark zeroth group, too
-
- return GNUNET_OK;
-}
-
-
-char *
-TALER_age_mask_to_string (
- const struct TALER_AgeMask *mask)
-{
- uint32_t bits = mask->bits;
- unsigned int n = 0;
- char *buf = GNUNET_malloc (32 * 3); // max characters possible
- char *pos = buf;
-
- if (NULL == buf)
- {
- return buf;
- }
-
- while (bits != 0)
- {
- bits >>= 1;
- n++;
- if (0 == (bits & 1))
- {
- continue;
- }
-
- if (n > 9)
- {
- *(pos++) = '0' + n / 10;
- }
- *(pos++) = '0' + n % 10;
-
- if (0 != (bits >> 1))
- {
- *(pos++) = ':';
- }
- }
- return buf;
-}
-
-
-/* ==================================================
- *
- * Age Restriction TALER_Extension implementation
- *
- * ==================================================
- */
-
-/**
- * @brief implements the TALER_Extension.disable interface.
- *
- * @param ext Pointer to the current extension
- */
-static void
-age_restriction_disable (
- struct TALER_Extension *ext)
-{
- if (NULL == ext)
- return;
-
- ext->config = NULL;
-
- if (NULL != ext->config_json)
- {
- json_decref (ext->config_json);
- ext->config_json = NULL;
- }
-
- TE_age_restriction_config.mask.bits = 0;
- TE_age_restriction_config.num_groups = 0;
-}
-
-
-/**
- * @brief implements the TALER_Extension.load_taler_config interface.
- *
- * @param ext Pointer to the current extension
- * @param cfg Handle to the GNUNET configuration
- * @return Error if extension for age restriction was set, but age groups were
- * invalid, OK otherwise.
- */
-static enum GNUNET_GenericReturnValue
-age_restriction_load_taler_config (
- struct TALER_Extension *ext,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- char *groups = NULL;
- enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR;
- struct TALER_AgeMask mask = {0};
-
- if ((GNUNET_YES !=
- GNUNET_CONFIGURATION_have_value (cfg,
- TALER_EXTENSION_SECTION_AGE_RESTRICTION,
- "ENABLED"))
- ||
- (GNUNET_YES !=
- GNUNET_CONFIGURATION_get_value_yesno (cfg,
- TALER_EXTENSION_SECTION_AGE_RESTRICTION,
- "ENABLED")))
- {
- /* Age restriction is not enabled */
- ext->config = NULL;
- ext->config_json = NULL;
- return GNUNET_OK;
- }
-
- /* Age restriction is enabled, extract age groups */
- if ((GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (cfg,
- TALER_EXTENSION_SECTION_AGE_RESTRICTION,
- "AGE_GROUPS"))
- &&
- (GNUNET_YES !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- TALER_EXTENSION_SECTION_AGE_RESTRICTION,
- "AGE_GROUPS",
- &groups)))
- return GNUNET_SYSERR;
-
-
- mask.bits = TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK;
- ret = GNUNET_OK;
-
- if (groups != NULL)
- {
- ret = TALER_parse_age_group_string (groups, &mask);
- if (GNUNET_OK != ret)
- mask.bits = TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK;
- }
-
- if (GNUNET_OK == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "setting age mask to %x with #groups: %d\n", mask.bits,
- __builtin_popcount (mask.bits) - 1);
- TE_age_restriction_config.mask.bits = mask.bits;
- TE_age_restriction_config.num_groups = __builtin_popcount (mask.bits) - 1; /* no underflow, first bit always set */
- ext->config = &TE_age_restriction_config;
-
- /* Note: we do now have TE_age_restriction_config set, however
- * ext->config_json is NOT set, i.e. the extension is not yet active! For
- * age restriction to become active, load_json_config must have been
- * called. */
- }
-
-
- GNUNET_free (groups);
- return ret;
-}
-
-
-/**
- * @brief implements the TALER_Extension.load_json_config interface.
- *
- * @param ext if NULL, only tests the configuration
- * @param jconfig the configuration as json
- */
-static enum GNUNET_GenericReturnValue
-age_restriction_load_json_config (
- struct TALER_Extension *ext,
- json_t *jconfig)
-{
- struct TALER_AgeMask mask = {0};
- enum GNUNET_GenericReturnValue ret;
-
- ret = TALER_JSON_parse_age_groups (jconfig, &mask);
- if (GNUNET_OK != ret)
- return ret;
-
- /* only testing the parser */
- if (ext == NULL)
- return GNUNET_OK;
-
- if (TALER_Extension_AgeRestriction != ext->type)
- return GNUNET_SYSERR;
-
- TE_age_restriction_config.mask.bits = mask.bits;
- TE_age_restriction_config.num_groups = 0;
-
- if (mask.bits > 0)
- {
- /* if the mask is not zero, the first bit MUST be set */
- if (0 == (mask.bits & 1))
- return GNUNET_SYSERR;
-
- TE_age_restriction_config.num_groups = __builtin_popcount (mask.bits) - 1;
- }
-
- ext->config = &TE_age_restriction_config;
-
- if (NULL != ext->config_json)
- json_decref (ext->config_json);
-
- ext->config_json = jconfig;
-
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "loaded new age restriction config with age groups: %s\n",
- TALER_age_mask_to_string (&mask));
-
- return GNUNET_OK;
-}
-
-
-/**
- * @brief implements the TALER_Extension.config_to_json interface.
- *
- * @param ext if NULL, only tests the configuration
- * @return configuration as json_t* object, maybe NULL
- */
-static json_t *
-age_restriction_config_to_json (
- const struct TALER_Extension *ext)
-{
- char *mask_str;
- json_t *conf;
-
- GNUNET_assert (NULL != ext);
-
- if (NULL == ext->config)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "age restriction not configured");
- return json_null ();
- }
-
- if (NULL != ext->config_json)
- {
- return json_copy (ext->config_json);
- }
-
- mask_str = TALER_age_mask_to_string (&TE_age_restriction_config.mask);
- conf = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("age_groups", mask_str)
- );
-
- return GNUNET_JSON_PACK (
- GNUNET_JSON_pack_bool ("critical", ext->critical),
- GNUNET_JSON_pack_string ("version", ext->version),
- GNUNET_JSON_pack_object_steal ("config", conf)
- );
-}
-
-
-/**
- * @brief implements the TALER_Extension.test_json_config interface.
- *
- * @param config configuration as json_t* to test
- * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise.
- */
-static enum GNUNET_GenericReturnValue
-age_restriction_test_json_config (
- const json_t *config)
-{
- struct TALER_AgeMask mask = {0};
-
- return TALER_JSON_parse_age_groups (config, &mask);
-}
-
-
-/* The extension for age restriction */
-struct TALER_Extension TE_age_restriction = {
- .next = NULL,
- .type = TALER_Extension_AgeRestriction,
- .name = "age_restriction",
- .critical = false,
- .version = "1",
- .config = NULL, // disabled per default
- .config_json = NULL,
- .disable = &age_restriction_disable,
- .test_json_config = &age_restriction_test_json_config,
- .load_json_config = &age_restriction_load_json_config,
- .config_to_json = &age_restriction_config_to_json,
- .load_taler_config = &age_restriction_load_taler_config,
-};
-
-enum GNUNET_GenericReturnValue
-TALER_extension_age_restriction_register ()
-{
- return TALER_extensions_add (&TE_age_restriction);
-}
-
-
-bool
-TALER_extensions_age_restriction_is_configured ()
-{
- return (0 != TE_age_restriction_config.mask.bits);
-}
-
-
-struct TALER_AgeMask
-TALER_extensions_age_restriction_ageMask ()
-{
- return TE_age_restriction_config.mask;
-}
-
-
-size_t
-TALER_extensions_age_restriction_num_groups ()
-{
- return TE_age_restriction_config.num_groups;
-}
-
-
-enum GNUNET_GenericReturnValue
-TALER_JSON_parse_age_groups (const json_t *root,
- struct TALER_AgeMask *mask)
-{
- enum GNUNET_GenericReturnValue ret;
- const char *str;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("age_groups",
- &str),
- GNUNET_JSON_spec_end ()
- };
-
- ret = GNUNET_JSON_parse (root,
- spec,
- NULL,
- NULL);
- if (GNUNET_OK == ret)
- TALER_parse_age_group_string (str, mask);
-
- GNUNET_JSON_parse_free (spec);
-
- return ret;
-}
-
-
-/* end of extension_age_restriction.c */
diff --git a/src/extensions/extensions.c b/src/extensions/extensions.c
index 0df0bae3..64574fc2 100644
--- a/src/extensions/extensions.c
+++ b/src/extensions/extensions.c
@@ -24,51 +24,53 @@
#include "taler_extensions.h"
#include "stdint.h"
-
/* head of the list of all registered extensions */
-static struct TALER_Extension *TE_extensions = NULL;
-
+static struct TALER_Extensions TE_extensions = {
+ .next = NULL,
+ .extension = NULL,
+};
-const struct TALER_Extension *
+const struct TALER_Extensions *
TALER_extensions_get_head ()
{
- return TE_extensions;
+ return &TE_extensions;
}
-enum GNUNET_GenericReturnValue
-TALER_extensions_add (
- struct TALER_Extension *extension)
+static enum GNUNET_GenericReturnValue
+add_extension (
+ const struct TALER_Extension *extension)
{
/* Sanity checks */
if ((NULL == extension) ||
(NULL == extension->name) ||
(NULL == extension->version) ||
(NULL == extension->disable) ||
- (NULL == extension->test_json_config) ||
- (NULL == extension->load_json_config) ||
- (NULL == extension->config_to_json) ||
- (NULL == extension->load_taler_config))
+ (NULL == extension->load_config) ||
+ (NULL == extension->manifest))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"invalid extension\n");
return GNUNET_SYSERR;
}
- if (NULL == TE_extensions) /* first extension ?*/
- TE_extensions = (struct TALER_Extension *) extension;
+ if (NULL == TE_extensions.extension) /* first extension ?*/
+ TE_extensions.extension = extension;
else
{
- struct TALER_Extension *iter;
- struct TALER_Extension *last;
+ struct TALER_Extensions *iter;
+ struct TALER_Extensions *last;
/* Check for collisions */
- for (iter = TE_extensions; NULL != iter; iter = iter->next)
+ for (iter = &TE_extensions;
+ NULL != iter && NULL != iter->extension;
+ iter = iter->next)
{
+ const struct TALER_Extension *ext = iter->extension;
last = iter;
- if (extension->type == iter->type ||
+ if (extension->type == ext->type ||
0 == strcasecmp (extension->name,
- iter->name))
+ ext->name))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"extension collision for `%s'\n",
@@ -78,7 +80,11 @@ TALER_extensions_add (
}
/* No collisions found, so add this extension to the list */
- last->next = extension;
+ {
+ struct TALER_Extensions *extn = GNUNET_new (struct TALER_Extensions);
+ extn->extension = extension;
+ last->next = extn;
+ }
}
return GNUNET_OK;
@@ -89,12 +95,12 @@ const struct TALER_Extension *
TALER_extensions_get_by_type (
enum TALER_Extension_Type type)
{
- for (const struct TALER_Extension *it = TE_extensions;
- NULL != it;
+ for (const struct TALER_Extensions *it = &TE_extensions;
+ NULL != it && NULL != it->extension;
it = it->next)
{
- if (it->type == type)
- return it;
+ if (it->extension->type == type)
+ return it->extension;
}
/* No extension found. */
@@ -109,8 +115,7 @@ TALER_extensions_is_enabled_type (
const struct TALER_Extension *ext =
TALER_extensions_get_by_type (type);
- return (NULL != ext &&
- TALER_extensions_is_enabled (ext));
+ return (NULL != ext && ext->enabled);
}
@@ -118,33 +123,34 @@ const struct TALER_Extension *
TALER_extensions_get_by_name (
const char *name)
{
- for (const struct TALER_Extension *it = TE_extensions;
+ for (const struct TALER_Extensions *it = &TE_extensions;
NULL != it;
it = it->next)
{
- if (0 == strcasecmp (name, it->name))
- return it;
+ if (0 == strcasecmp (name, it->extension->name))
+ return it->extension;
}
- /* No extension found. */
+ /* No extension found, try to load it. */
+
return NULL;
}
enum GNUNET_GenericReturnValue
-TALER_extensions_verify_json_config_signature (
- json_t *extensions,
+TALER_extensions_verify_manifests_signature (
+ json_t *manifests,
struct TALER_MasterSignatureP *extensions_sig,
struct TALER_MasterPublicKeyP *master_pub)
{
- struct TALER_ExtensionConfigHashP h_config;
+ struct TALER_ExtensionManifestsHashP h_manifests;
if (GNUNET_OK !=
- TALER_JSON_extensions_config_hash (extensions,
- &h_config))
+ TALER_JSON_extensions_manifests_hash (manifests,
+ &h_manifests))
return GNUNET_SYSERR;
if (GNUNET_OK !=
- TALER_exchange_offline_extension_config_hash_verify (
- &h_config,
+ TALER_exchange_offline_extension_manifests_hash_verify (
+ &h_manifests,
master_pub,
extensions_sig))
return GNUNET_NO;
@@ -178,7 +184,8 @@ configure_extension (
{
struct LoadConfClosure *col = cls;
const char *name;
- const struct TALER_Extension *extension;
+ char *lib_name;
+ struct TALER_Extension *extension;
if (GNUNET_OK != col->error)
return;
@@ -190,33 +197,49 @@ configure_extension (
name = section + sizeof(TALER_EXTENSION_SECTION_PREFIX) - 1;
- if (NULL ==
- (extension = TALER_extensions_get_by_name (name)))
+
+ /* Load the extension library */
+ GNUNET_asprintf (&lib_name,
+ "libtaler_extension_%s",
+ name);
+ extension = GNUNET_PLUGIN_load (
+ lib_name,
+ (void *) col->cfg);
+ if (NULL == extension)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unsupported extension `%s` (section [%s]).\n", name,
+ "Couldn't load extension library to `%s` (section [%s]).\n",
+ name,
section);
col->error = GNUNET_SYSERR;
return;
}
- if (GNUNET_OK !=
- extension->load_taler_config (
- (struct TALER_Extension *) extension,
- col->cfg))
+
+ if (GNUNET_OK != add_extension (extension))
{
+ /* TODO: Ignoring return values here */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Couldn't parse configuration for extension `%s` (section [%s]).\n",
+ "Couldn't add extension `%s` (section [%s]).\n",
name,
section);
col->error = GNUNET_SYSERR;
+ GNUNET_PLUGIN_unload (
+ lib_name,
+ (void *) col->cfg);
return;
}
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "extension library '%s' loaded\n",
+ lib_name);
}
+static bool extensions_loaded = false;
+
enum GNUNET_GenericReturnValue
-TALER_extensions_load_taler_config (
+TALER_extensions_init (
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
struct LoadConfClosure col = {
@@ -224,15 +247,22 @@ TALER_extensions_load_taler_config (
.error = GNUNET_OK,
};
+ if (extensions_loaded)
+ return GNUNET_OK;
+
GNUNET_CONFIGURATION_iterate_sections (cfg,
&configure_extension,
&col);
+
+ if (GNUNET_OK == col.error)
+ extensions_loaded = true;
+
return col.error;
}
enum GNUNET_GenericReturnValue
-TALER_extensions_is_json_config (
+TALER_extensions_parse_manifest (
json_t *obj,
int *critical,
const char **version,
@@ -265,22 +295,23 @@ TALER_extensions_is_json_config (
enum GNUNET_GenericReturnValue
-TALER_extensions_load_json_config (
+TALER_extensions_load_manifests (
json_t *extensions)
{
const char*name;
- json_t *blob;
+ json_t *manifest;
GNUNET_assert (NULL != extensions);
GNUNET_assert (json_is_object (extensions));
- json_object_foreach (extensions, name, blob)
+ json_object_foreach (extensions, name, manifest)
{
int critical;
const char *version;
json_t *config;
- const struct TALER_Extension *extension =
- TALER_extensions_get_by_name (name);
+ struct TALER_Extension *extension = (struct
+ TALER_Extension *)
+ TALER_extensions_get_by_name (name);
if (NULL == extension)
{
@@ -291,45 +322,83 @@ TALER_extensions_load_json_config (
/* load and verify criticality, version, etc. */
if (GNUNET_OK !=
- TALER_extensions_is_json_config (
- blob, &critical, &version, &config))
+ TALER_extensions_parse_manifest (
+ manifest, &critical, &version, &config))
return GNUNET_SYSERR;
if (critical != extension->critical
|| 0 != strcmp (version, extension->version) // TODO: libtool compare?
|| NULL == config
- || GNUNET_OK != extension->test_json_config (config))
+ || GNUNET_OK != extension->load_config (NULL, config))
return GNUNET_SYSERR;
/* This _should_ work now */
if (GNUNET_OK !=
- extension->load_json_config ((struct TALER_Extension *) extension,
- config))
+ extension->load_config (extension, config))
return GNUNET_SYSERR;
+
+ extension->enabled = true;
}
/* make sure to disable all extensions that weren't mentioned in the json */
- for (const struct TALER_Extension *it = TALER_extensions_get_head ();
+ for (const struct TALER_Extensions *it = TALER_extensions_get_head ();
NULL != it;
it = it->next)
{
- if (NULL == json_object_get (extensions, it->name))
- it->disable ((struct TALER_Extension *) it);
+ if (NULL == json_object_get (extensions, it->extension->name))
+ it->extension->disable ((struct TALER_Extension *) it);
}
return GNUNET_OK;
}
-bool
-TALER_extensions_age_restriction_is_enabled ()
+enum GNUNET_GenericReturnValue
+TALER_extensions_from_policy_details (
+ const json_t *policy_details,
+ const struct TALER_Extension **extension,
+ char **error_hint)
{
- const struct TALER_Extension *age =
- TALER_extensions_get_by_type (TALER_Extension_AgeRestriction);
+ const json_t *jtype;
+ const char *type;
+
+ *extension = NULL;
+ *error_hint = NULL;
+
+ if ((NULL == policy_details) ||
+ (! json_is_object (policy_details)))
+ {
+ *error_hint = "invalid policy object";
+ return GNUNET_SYSERR;
+ }
+
+ jtype = json_object_get (policy_details, "type");
+ if (NULL == jtype)
+ {
+ *error_hint = "no type in policy object";
+ return GNUNET_SYSERR;
+ }
+
+ type = json_string_value (jtype);
+ if (NULL == type)
+ {
+ *error_hint = "invalid type in policy object";
+ return GNUNET_SYSERR;
+ }
- return (NULL != age &&
- NULL != age->config_json &&
- TALER_extensions_age_restriction_is_configured ());
+ *extension = TALER_extensions_get_by_name (type);
+ if ((NULL == *extension) ||
+ (NULL == (*extension)->parse_policy_details))
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unsupported extension policy '%s' requested\n",
+ type);
+ *extension = NULL;
+ return GNUNET_NO;
+ }
+
+ return GNUNET_OK;
}
diff --git a/src/extensions/policy_brandt_vickrey_auction/Makefile.am b/src/extensions/policy_brandt_vickrey_auction/Makefile.am
new file mode 100644
index 00000000..63fa6ce6
--- /dev/null
+++ b/src/extensions/policy_brandt_vickrey_auction/Makefile.am
@@ -0,0 +1,34 @@
+# This Makefile.am is in the public domain
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/include \
+ $(LIBGCRYPT_CFLAGS) \
+ $(POSTGRESQL_CPPFLAGS)
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIB = -lgcov
+endif
+
+
+# Auction of Brandt type as an extension library
+
+plugindir = $(libdir)/taler
+
+plugin_LTLIBRARIES = \
+ libtaler_extension_policy_brandt_vickrey_auction.la
+
+libtaler_extension_policy_brandt_vickrey_auction_la_LDFLAGS = \
+ -version-info 0:0:0 \
+ -no-undefined
+
+libtaler_extension_policy_brandt_vickrey_auction_la_SOURCES = \
+ policy_brandt_vickrey_auction.c
+
+libtaler_extension_policy_brandt_vickrey_auction_la_LIBADD = \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetjson \
+ -lgnunetutil \
+ -ljansson \
+ $(XLIB)
diff --git a/src/extensions/policy_brandt_vickrey_auction/policy_brandt_vickrey_auction.c b/src/extensions/policy_brandt_vickrey_auction/policy_brandt_vickrey_auction.c
new file mode 100644
index 00000000..e00f810f
--- /dev/null
+++ b/src/extensions/policy_brandt_vickrey_auction/policy_brandt_vickrey_auction.c
@@ -0,0 +1,760 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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 policy_brandt_vickery_auction.c
+ * @brief Extension for replay of auctions of type Brandt
+ * @author Özgür Kesim
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_extensions.h"
+#include "../../exchange/taler-exchange-httpd.h"
+#include "taler_mhd_lib.h"
+#include "stdint.h"
+#include <microhttpd.h>
+
+#define POLICY_AUCTION "policy_brandt_vickery_auction"
+#define LOG_PREFIX "[policy_brandt_vickery_auction] "
+#define MAX_RESULT_SIZE 10 * 1024
+
+/* (public) configuration of this extension */
+/* TODO: these fields need to be set in the init handler */
+static struct TALER_ExtensionPolicyBrandtVickreyAuctionConfig BV_config = {
+ .max_bidders = 10,
+ .max_prices = 10,
+ .auction_fee = {
+ .value = 0,
+ .fraction = 0,
+ .currency = {'E', 'U', 'R', 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ },
+};
+
+/* Path to the replay program. */
+static char *replay_program;
+
+
+/* supported currency */
+static char *currency;
+
+/* This is basically BRANDT_Result with an extra string field */
+struct result
+{
+ uint16_t bidder;
+ uint16_t price_idx;
+ const char *price;
+};
+
+/*
+ * @brief Transcript information
+ *
+ */
+struct transcript
+{
+ /*
+ * The first couple of fields are from a JSON transcript
+ */
+
+ /* Public key of seller */
+ struct GNUNET_CRYPTO_EddsaPublicKey seller_pub;
+
+ /* Payto URL */
+ const char *payto;
+
+ /* Number of bidders + 1 (for seller) */
+ uint16_t n;
+
+ /* (n-1) public keys of bidders */
+ struct GNUNET_CRYPTO_EddsaPublicKey *bidder_pub;
+
+ /* Type of auction, see libbrandt */
+ uint16_t m;
+
+ /* Auction public outcome? */
+ bool public;
+
+ /* Start date of the auction */
+ struct GNUNET_TIME_Timestamp time_start;
+
+ /* End date of the auction */
+ struct GNUNET_TIME_Relative time_round;
+
+ /* Number of prices */
+ uint16_t k;
+
+ /* Prices, must be length k */
+ struct TALER_Amount *prices;
+
+ /* Expected winner(s), maybe NULL */
+ struct result *expected;
+ size_t expected_len;
+
+ /*
+ * These are the results from the replay via the external program.
+ */
+ struct result *results;
+ size_t results_len;
+};
+
+/**
+ * @brief returns an JSON with the error
+ */
+static enum GNUNET_GenericReturnValue
+json_error (json_t **output,
+ char *error, ...)
+{
+ va_list ap;
+ int n = 0;
+ char buf[4096];
+ GNUNET_assert (error);
+
+ va_start (ap, error);
+ n = vsprintf (buf, error, ap);
+ va_end (ap);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ LOG_PREFIX "got error: %s\n",
+ n < 0 ? error: buf);
+
+ *output = json_pack ("{s:s}",
+ "error",
+ n < 0 ? error : buf);
+ GNUNET_assert (*output);
+
+ return GNUNET_SYSERR;
+};
+
+
+/*
+ * @brief Parses a given json as transcript.
+ *
+ * @param[in] jtr JSON input
+ * @param[out] tr Parsed transcript data
+ * @param[out] jerror JSON output for errors
+ * @return GNUNET_OK on succes
+ *
+ * TODO:
+ * - parse and verify signatures
+ */
+static enum GNUNET_GenericReturnValue
+parse_transcript (const json_t *jtr,
+ struct transcript *tr,
+ json_t **jerror)
+{
+ json_t *auc;
+
+ // TODO: struct GNUNET_CRYPTO_EddsaSignature sig;
+
+ GNUNET_assert (jtr);
+ GNUNET_assert (tr);
+
+ // Parse auction
+ {
+ char *perr;
+ unsigned int eline;
+ struct GNUNET_JSON_Specification au_spec[] = {
+ GNUNET_JSON_spec_bool ("public", &tr->public),
+ GNUNET_JSON_spec_uint16 ("type", &tr->m),
+ GNUNET_JSON_spec_fixed_auto ("pubkey", &tr->seller_pub),
+ GNUNET_JSON_spec_timestamp ("time_start", &tr->time_start),
+ GNUNET_JSON_spec_relative_time ("time_round", &tr->time_round),
+ GNUNET_JSON_spec_string ("payto_uri", &tr->payto),
+ GNUNET_JSON_spec_end ()
+ };
+
+ auc = json_object_get (jtr, "auction");
+ if (NULL == auc)
+ return json_error (jerror,
+ "no auction found in transcript");
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (auc,
+ au_spec,
+ (const char **) &perr,
+ &eline))
+ return json_error (jerror,
+ perr);
+
+ // Prices...
+ {
+ size_t idx;
+ json_t *val;
+ json_t *prices;
+
+ prices = json_object_get (auc, "prices");
+ if (! json_is_array (prices))
+ return json_error (jerror,
+ "no prices found");
+
+ tr->k = json_array_size (prices);
+
+ tr->prices = GNUNET_new_array (tr->k, struct TALER_Amount);
+ json_array_foreach (prices, idx, val)
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount (NULL,
+ currency,
+ &(tr->prices[idx])),
+ GNUNET_JSON_spec_end (),
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (val,
+ spec,
+ NULL,
+ NULL))
+ return json_error (jerror,
+ "price no. %ld couldn't be parsed",
+ idx + 1);
+ }
+ }
+ }
+
+ // Bidders
+ {
+ size_t idx;
+ json_t *val;
+ json_t *bidders;
+
+ bidders = json_object_get (jtr, "bidders");
+ if (! bidders || ! json_is_array (bidders))
+ return json_error (jerror,
+ "no bidders found");
+
+ tr->n = json_array_size (bidders);
+
+ tr->bidder_pub = GNUNET_new_array (tr->n, struct
+ GNUNET_CRYPTO_EddsaPublicKey);
+ json_array_foreach (bidders, idx, val)
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto (NULL,
+ &(tr->bidder_pub[idx])),
+ GNUNET_JSON_spec_end (),
+ };
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (val,
+ spec,
+ NULL,
+ NULL))
+ return json_error (jerror,
+ "bidder no %ld public key couldn't be parsed",
+ idx + 1);
+ }
+ }
+
+ // TODO: parse and verify signatures from bidders of the auction
+
+
+ // Messages
+ {
+ size_t nm;
+ json_t *messages = json_object_get (jtr, "transcript");
+
+ if (! json_is_array (messages))
+ return json_error (jerror,
+ "no messages found");
+
+
+ nm = json_array_size (messages);
+
+ if (nm != (4 * tr->n))
+ return json_error (jerror,
+ "not the right no. of messages found");
+
+ /* TODO: parse and evaluate signatures */
+ }
+
+ // Winners
+ {
+ size_t idx;
+ json_t *val;
+ json_t *winners = json_object_get (jtr, "winners");
+
+ if (! json_is_array (winners))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ LOG_PREFIX "winners not provided, continuing without\n");
+ goto DONE;
+ }
+
+ tr->expected_len = json_array_size (winners);
+ tr->expected = GNUNET_new_array (tr->expected_len,
+ struct result);
+
+ json_array_foreach (winners, idx, val) {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_uint16 ("bidder",
+ &(tr->expected[idx].bidder)),
+ GNUNET_JSON_spec_uint16 ("price_idx",
+ &(tr->expected[idx].price_idx)),
+ GNUNET_JSON_spec_string ("price",
+ &(tr->expected[idx].price)),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (val,
+ spec,
+ NULL,
+ NULL))
+ return json_error (jerror,
+ "couldn't parse winner no. %ld",
+ idx + 1);
+ }
+ }
+
+ // TODO: parse and evalue sig of seller
+
+// TODO: check for max values
+
+DONE:
+
+ *jerror = NULL;
+ return GNUNET_OK;
+}
+
+
+/**
+ * @brief replay an auction using the external program
+ *
+ * @param[in] root The original JSON transcript
+ * @param[in] transcript The transcript object parsed so far
+ * @param[out] result The JSON result from the program
+ * @return GNUNET_OK on success
+ *
+ * TODO: Make this resumable
+ */
+static enum GNUNET_GenericReturnValue
+replay_transcript (const json_t*root,
+ struct transcript *tr,
+ json_t **result)
+{
+ struct GNUNET_DISK_PipeHandle *pi;
+ struct GNUNET_DISK_PipeHandle *po;
+ const struct GNUNET_DISK_FileHandle *fd;
+ struct GNUNET_OS_Process *proc;
+
+ pi = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_WRITE);
+ po = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_READ);
+ proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ERR,
+ pi, po, NULL,
+ replay_program,
+ replay_program,
+ NULL);
+ if (NULL == proc)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ LOG_PREFIX "couldn't create auction replay program '%s'\n",
+ replay_program);
+
+ return json_error (result, "internal error");
+ }
+
+ // Write original transcript JSON to stdin
+ {
+ ssize_t sz;
+ char *str;
+ size_t str_len;
+
+
+ fd = GNUNET_DISK_pipe_handle (pi, GNUNET_DISK_PIPE_END_WRITE);
+ str = json_dumps (root, JSON_COMPACT);
+ str_len = strlen (str);
+ sz = GNUNET_DISK_file_write (fd,
+ str,
+ str_len);
+ free (str);
+ if (sz != str_len)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ LOG_PREFIX "couldn't write all data to replay_program\n");
+ }
+ }
+
+ // Read output from stdout
+ {
+ ssize_t sz;
+ char buf[MAX_RESULT_SIZE];
+ json_error_t error;
+ json_t *res;
+
+ fd = GNUNET_DISK_pipe_handle (po, GNUNET_DISK_PIPE_END_READ);
+
+ sz = GNUNET_DISK_file_read (fd,
+ buf,
+ sizeof(buf));
+ if (GNUNET_SYSERR == sz)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ LOG_PREFIX "couldn't read data from replay_program\n");
+ return json_error (result, "internal error");
+ }
+
+ buf[sz] = 0;
+ res = json_loads (buf,
+ JSON_DECODE_ANY,
+ &error);
+
+ if (! res)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ LOG_PREFIX
+ "couldn't parse response from replay_program: %s (for '%s')\n",
+ error.text,
+ buf);
+ return json_error (result, error.text);
+ }
+
+ // Handle error case first
+ {
+ json_t *err = json_object_get (res,
+ "error");
+ if (NULL != err)
+ {
+ *result = json_copy (res);
+ json_decref (res);
+ return GNUNET_SYSERR;
+ }
+ }
+
+ // Parse the result
+ {
+ json_t *winners = json_object_get (res,
+ "winners");
+ if ((NULL == winners) ||
+ (! json_is_array (winners)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ LOG_PREFIX
+ "replay program didn't return a known result type, instead: '%s'\n",
+ json_dumps (res, JSON_INDENT (2)));
+ return json_error (result, "internal error");
+ }
+
+ {
+ // TODO: check each winner with tr->expected, if applicable
+ json_object_set (res, "exchange_sig", json_string (
+ "sig(priv_E, winners)"));
+
+ }
+
+ // TODO: return own result object.
+ *result = json_copy (res);
+ json_decref (res);
+ }
+
+ }
+
+ if (GNUNET_OK != GNUNET_OS_process_wait (proc))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ LOG_PREFIX "error while launching auction replay program '%s'\n",
+ replay_program);
+
+ json_object_clear (*result);
+ return json_error (result, "internal error");
+ }
+
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * @brief implements the TALER_Extension.disable interface.
+ *
+ * @param ext Pointer to the current extension
+ */
+static void
+auction_disable (
+ struct TALER_Extension *ext)
+{
+ ext->config = NULL;
+ ext->enabled = false;
+}
+
+
+/**
+ * @brief implements the TALER_Extension.manifest interface.
+ *
+ * @param ext if NULL, only tests the configuration
+ * @return configuration as json_t* object, maybe NULL
+ */
+static json_t *
+auction_manifest (
+ const struct TALER_Extension *ext)
+{
+ struct TALER_ExtensionPolicyBrandtVickreyAuctionConfig *conf = ext->config;
+ GNUNET_assert (conf);
+
+ json_t *config = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_int64 ("max_bidders", conf->max_bidders),
+ GNUNET_JSON_pack_int64 ("max_prices", conf->max_prices),
+ TALER_JSON_pack_amount ("auction_fee", &conf->auction_fee));
+ GNUNET_assert (config);
+
+ return GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_bool ("critical", ext->critical),
+ GNUNET_JSON_pack_string ("version", ext->version),
+ GNUNET_JSON_pack_object_steal ("config", config));
+}
+
+
+/**
+ * @brief implements the TALER_Extension.load_config interface.
+ *
+ * @param ext if NULL, only tests the configuration
+ * @param jconfig the configuration as json
+ */
+static enum GNUNET_GenericReturnValue
+auction_load_config (
+ struct TALER_Extension *ext,
+ json_t *jconfig)
+{
+ /* TODO: parse configuration */
+ ext->enabled = true;
+ return GNUNET_OK;
+}
+
+
+/**
+ * @brief implements the TALER_Extension.http_get_handler
+ */
+static MHD_RESULT
+auction_http_get_handler (
+ struct MHD_Connection *connection,
+ const char *const args[])
+{
+ /* TODO: return some meta-data about supported version, limits, etc.*/
+
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ LOG_PREFIX "auction_http_get_handler not implemented yet\n");
+
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_IMPLEMENTED,
+ TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
+ "auction_http_get_handler not implemented yet\n");
+
+}
+
+
+/**
+ * @brief implements the TALER_Extension.http_post_handler
+ *
+ * TODO: make this non-blocking
+ */
+static MHD_RESULT
+auction_http_post_handler (
+ struct MHD_Connection *connection,
+ const json_t *root,
+ const char *const args[])
+{
+ struct transcript tr = {};
+ enum GNUNET_GenericReturnValue ret;
+ json_t *result1;
+ json_t *result2;
+
+ ret = parse_transcript (root,
+ &tr,
+ &result1);
+ if (GNUNET_OK != ret)
+ return TALER_MHD_reply_json_steal (connection,
+ result1,
+ MHD_HTTP_BAD_REQUEST);
+ GNUNET_assert (NULL == result1);
+
+ ret = replay_transcript (root,
+ &tr,
+ &result2);
+
+ return TALER_MHD_reply_json_steal (connection,
+ result2,
+ GNUNET_OK == ret?
+ MHD_HTTP_OK :
+ MHD_HTTP_BAD_REQUEST);
+}
+
+
+/**
+ * @brief implements the TALER_Extensions.parse_policy_details interface.
+ *
+ * @param[in] input The policy_details for this handler during deposit
+ * @param[out] serial On success will contain the serial-ID under which the
+ * @param[out] deadline On success will contain a deadline, might be "forever"
+ * exchange should store the policy_details in the policy_details table.
+ * @return GNUNET_OK if the request was OK
+ */
+enum GNUNET_GenericReturnValue
+auction_parse_policy_details (
+ const json_t *input,
+ struct TALER_ExtensionsPolicySerialID *serial,
+ struct GNUNET_TIME_Timestamp *deadline)
+{
+ enum GNUNET_GenericReturnValue ret = GNUNET_NO;
+ struct GNUNET_CRYPTO_EddsaPublicKey pub;
+ struct GNUNET_HashCode hc;
+ struct GNUNET_JSON_Specification spec[] = {
+ /* We ignore the "type" field as it must have been parsed already upstream
+ * - or this handler wouldn't have been called in first place. */
+ GNUNET_JSON_spec_fixed_auto ("bidder_pub", &pub),
+ GNUNET_JSON_spec_fixed_auto ("h_auction", &hc),
+ GNUNET_JSON_spec_timestamp ("deadline", deadline),
+ GNUNET_JSON_spec_end (),
+ };
+
+ GNUNET_assert (serial);
+ GNUNET_assert (deadline);
+
+ do {
+ ret = GNUNET_JSON_parse (input,
+ spec,
+ NULL,
+ NULL);
+
+ if (GNUNET_OK != ret)
+ break;
+
+ /* FIXME: check the deadline */
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ LOG_PREFIX "check of deadline %ld not implemented!\n",
+ deadline->abs_time.abs_value_us);
+
+ /* Create serial as H(bidder_pub, h_auction) */
+ {
+ struct GNUNET_HashContext *hc = GNUNET_CRYPTO_hash_context_start ();
+ GNUNET_CRYPTO_hash_context_read (hc,
+ &pub,
+ sizeof(pub));
+ GNUNET_CRYPTO_hash_context_read (hc,
+ &hc,
+ sizeof(hc));
+ GNUNET_CRYPTO_hash_context_finish (hc,
+ &serial->hash);
+ }
+
+ ret = GNUNET_OK;
+ } while(0);
+
+ return ret;
+}
+
+
+/* The extension struct for auctions of brandt-style */
+struct TALER_Extension TE_auction_brandt = {
+ .type = TALER_Extension_PolicyBrandtVickeryAuction,
+ .name = POLICY_AUCTION,
+ .critical = false,
+ .version = "0",
+ .enabled = false, /* disabled per default */
+ .config = &BV_config,
+ .disable = &auction_disable,
+ .load_config = &auction_load_config,
+ .manifest = &auction_manifest,
+ .parse_policy_details = &auction_parse_policy_details,
+ .http_get_handler = &auction_http_get_handler,
+ .http_post_handler = &auction_http_post_handler,
+};
+
+
+/**
+ * ===========================================
+ * Handler for GNUNET_PLUGIN_load and _unload
+ * ===========================================
+ */
+
+/**
+ * @brief Initialization function for the extension.
+ * Will be called by GNUNET_PLUGIN_load.
+ *
+ * @param arg Configuration - ptr to GNUNET_CONFIGURATION_Handle
+ * @return Pointer to TE_auction_brandt
+ */
+struct TALER_Extension *
+libtaler_extension_policy_brandt_vickery_auction_init (void *arg)
+{
+ const struct GNUNET_CONFIGURATION_Handle *cfg = arg;
+
+
+ if (GNUNET_OK !=
+ TALER_config_get_currency (cfg,
+ &currency))
+ return NULL;
+
+ if (GNUNET_SYSERR ==
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ TALER_EXTENSION_SECTION_PREFIX
+ POLICY_AUCTION,
+ "REPLAY_PROGRAM",
+ &replay_program))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ TALER_EXTENSION_SECTION_PREFIX POLICY_AUCTION,
+ "REPLAY_PROGRAM");
+ return NULL;
+ }
+
+ /* check if replay_program is actually an executable */
+ {
+ struct stat sb;
+
+ if (0 != stat (replay_program, &sb))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ LOG_PREFIX "replay_program '%s' not found\n",
+ replay_program);
+ return NULL;
+ }
+
+ if ( (sb.st_mode & S_IFDIR) ||
+ ! (sb.st_mode & S_IXUSR))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ LOG_PREFIX "replay_program '%s' is not an executable\n",
+ replay_program);
+ return NULL;
+ }
+
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ LOG_PREFIX "loading... using replay_program '%s'\n",
+ replay_program);
+
+ /* TODO: read other config parameters and generate configuration */
+
+ return &TE_auction_brandt;
+}
+
+
+/**
+ * @brief Tear-down function for the extension.
+ * Will be called by GNUNET_PLUGIN_unload.
+ *
+ * @param ignored
+ * @return null
+ */
+void *
+libtaler_extension_policy_brandt_vickery_auction_done (void *arg)
+{
+ auction_disable (&TE_auction_brandt);
+ GNUNET_free (replay_program);
+ replay_program = NULL;
+
+ return NULL;
+}
+
+
+/* end of policy_brandt_vickery_auction.c */