aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/exchange-tools/taler-exchange-offline.c6
-rw-r--r--src/exchange/taler-exchange-httpd.c43
-rw-r--r--src/exchange/taler-exchange-httpd_extensions.c17
-rw-r--r--src/exchange/taler-exchange-httpd_keys.c13
-rw-r--r--src/extensions/age_restriction/extension_age_restriction.c9
-rw-r--r--src/extensions/auction_brandt/extension_auction_brandt.c309
-rw-r--r--src/include/taler_extensions.h13
-rw-r--r--src/lib/exchange_api_handle.c3
-rw-r--r--src/testing/testing_api_cmd_batch_withdraw.c2
-rw-r--r--src/testing/testing_api_cmd_withdraw.c2
10 files changed, 380 insertions, 37 deletions
diff --git a/src/exchange-tools/taler-exchange-offline.c b/src/exchange-tools/taler-exchange-offline.c
index e7cb94b5..3d980c27 100644
--- a/src/exchange-tools/taler-exchange-offline.c
+++ b/src/exchange-tools/taler-exchange-offline.c
@@ -4255,13 +4255,17 @@ do_extensions_show (char *const *args)
GNUNET_assert (NULL != exts);
for (it = TALER_extensions_get_head ();
- NULL != it;
+ NULL != it && NULL != it->extension;
it = it->next)
+ {
+ const struct TALER_Extension *extension = it->extension;
+
GNUNET_assert (0 ==
json_object_set_new (exts,
it->extension->name,
it->extension->config_to_json (
it->extension)));
+ }
obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_object_steal ("extensions",
exts));
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
index d7651d79..68fc9fb7 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -1040,6 +1040,42 @@ handle_post_auditors (struct TEH_RequestContext *rc,
root);
}
+/**
+ * Handle GET "/extensions/..." requests.
+ *
+ * @param rc request context
+ * @param args array of additional options
+ * @return MHD result code
+ */
+static MHD_RESULT
+handle_get_extensions (struct TEH_RequestContext *rc,
+ 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_get_handler)
+ return MHD_HTTP_NOT_IMPLEMENTED;
+
+ return ext->http_get_handler (
+ rc->connection,
+ &args[1]);
+}
+
/**
* Handle POST "/extensions/..." requests.
@@ -1301,6 +1337,13 @@ handle_mhd_request (void *cls,
/* extensions endpoints */
{
.url = "extensions",
+ .method = MHD_HTTP_METHOD_GET,
+ .handler.get = &handle_get_extensions,
+ .nargs = 4, /* Arbitrary upper bound */
+ .nargs_is_upper_bound = true,
+ },
+ {
+ .url = "extensions",
.method = MHD_HTTP_METHOD_POST,
.handler.post = &handle_post_extensions,
.nargs = 4, /* Arbitrary upper bound */
diff --git a/src/exchange/taler-exchange-httpd_extensions.c b/src/exchange/taler-exchange-httpd_extensions.c
index 2a99d7a2..2aee1b5c 100644
--- a/src/exchange/taler-exchange-httpd_extensions.c
+++ b/src/exchange/taler-exchange-httpd_extensions.c
@@ -78,6 +78,7 @@ extension_update_event_cb (void *cls,
}
// Get the config from the database as string
+ if (extension->has_config)
{
char *config_str = NULL;
enum GNUNET_DB_QueryStatus qs;
@@ -117,26 +118,26 @@ extension_update_event_cb (void *cls,
err.text,
err.source);
GNUNET_break (0);
- free(config_str);
+ free (config_str);
return;
}
// Call the parser for the extension
ret = extension->load_json_config (
(struct TALER_Extension *) extension,
- json_object_get(config, "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: %s\n",
extension->name,
- config_str);
+ config_str);
GNUNET_break (0);
}
- free(config_str);
- json_decref(config);
+ free (config_str);
+ json_decref (config);
}
/* Special case age restriction: Update global flag and mask */
@@ -190,12 +191,16 @@ TEH_extensions_init ()
it = it->next)
{
const struct TALER_Extension *ext = it->extension;
+ uint32_t typ = htonl (ext->type);
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));
+
+ extension_update_event_cb (NULL,
+ &typ,
+ sizeof(typ));
free (conf);
}
diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c
index 4fb8a717..4761f314 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -1916,18 +1916,23 @@ create_krd (struct TEH_KeyStateHandle *ksh,
/* flag our findings so far */
has_extensions = true;
- GNUNET_assert (NULL != extension->config_json);
ext = GNUNET_JSON_PACK (
GNUNET_JSON_pack_bool ("critical",
extension->critical),
GNUNET_JSON_pack_string ("version",
- extension->version),
- GNUNET_JSON_pack_object_incref ("config",
- extension->config_json)
+ extension->version)
);
GNUNET_assert (NULL != ext);
+ if (extension->has_config)
+ {
+ GNUNET_assert (extension->config_json);
+ json_object_set_new (ext,
+ "config",
+ extension->config_json);
+ }
+
r = json_object_set_new (
extensions,
extension->name,
diff --git a/src/extensions/age_restriction/extension_age_restriction.c b/src/extensions/age_restriction/extension_age_restriction.c
index 1399fbc7..697d066f 100644
--- a/src/extensions/age_restriction/extension_age_restriction.c
+++ b/src/extensions/age_restriction/extension_age_restriction.c
@@ -105,8 +105,8 @@ age_restriction_load_json_config (
json_decref (ext->config_json);
ext->enabled = true;
- ext->config_json = json_copy(jconfig);
- json_decref(jconfig);
+ ext->config_json = json_copy (jconfig);
+ json_decref (jconfig);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"loaded new age restriction config with age groups: %s\n",
@@ -155,7 +155,7 @@ age_restriction_config_to_json (
GNUNET_JSON_pack_string ("age_groups", mask_str)
);
- free(mask_str);
+ free (mask_str);
return GNUNET_JSON_PACK (
GNUNET_JSON_pack_bool ("critical", ext->critical),
@@ -188,6 +188,7 @@ struct TALER_Extension TE_extension_age_restriction = {
.critical = false,
.version = "1",
.enabled = false, /* disabled per default */
+ .has_config = true, /* we need to store configuration */
.config = NULL,
.config_json = NULL,
.disable = &age_restriction_disable,
@@ -264,7 +265,7 @@ libtaler_extension_age_restriction_init (void *arg)
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),
+ TALER_age_mask_to_string (&AR_config.mask),
__builtin_popcount (AR_config.mask.bits) - 1);
TE_extension_age_restriction.config = &AR_config;
diff --git a/src/extensions/auction_brandt/extension_auction_brandt.c b/src/extensions/auction_brandt/extension_auction_brandt.c
index a6efd94b..a5f3af8c 100644
--- a/src/extensions/auction_brandt/extension_auction_brandt.c
+++ b/src/extensions/auction_brandt/extension_auction_brandt.c
@@ -26,11 +26,245 @@
#include "stdint.h"
#include <microhttpd.h>
-#define EXTENSION_NAME "auction_brandt"
+#define AUCTION_BRANDT "auction_brandt"
/* Path to the replay program. */
static char *replay_program;
+/* This is basically BRANDT_Result with an extra string field */
+struct result
+{
+ uint16_t bidder;
+ uint16_t price_idx;
+ const char *price;
+};
+
+/*
+ * TODO: Transcript information
+ */
+struct transcript
+{
+ // All fields from json come here.
+ uint16_t n; // #bidders + 1
+ uint16_t k; // #prices
+ uint16_t m; // type of auction
+ struct GNUNET_TIME_Absolute time_start;
+ struct GNUNET_TIME_Relative time_round;
+ bool public;
+ char **prices; // Must be of length k. We do not parse those
+ // struct msg *msgs; // Array must be of length 4*n
+
+ // struct BRANDT_Auction *auction;
+
+ struct result *results;
+ size_t results_len;
+ struct result *expected;
+ size_t expected_len;
+ uint16_t id;
+ struct GNUNET_CRYPTO_EccDlogContext *edc;
+};
+
+/**
+ * @brief returns an JSON with the error
+ */
+static enum GNUNET_GenericReturnValue
+json_error (json_t **output,
+ char *error)
+{
+ GNUNET_assert (error);
+
+ *output = json_pack ("{s:s}", "error", error);
+ GNUNET_assert (*output);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "[auction_brandt] got error: %s\n",
+ error);
+
+ return GNUNET_SYSERR;
+};
+
+/**
+ * @brief returns an JSON with the result
+ */
+static enum GNUNET_GenericReturnValue
+json_result (json_t **output,
+ const struct transcript *tr)
+{
+ json_t *results;
+
+ GNUNET_assert (NULL != tr);
+
+ *output = json_object ();
+ results = json_array ();
+ GNUNET_assert (*output);
+ GNUNET_assert (results);
+
+ for (size_t i = 0; i < tr->results_len; i++)
+ {
+ json_t *result = json_pack ("{s:i, s:s}",
+ "bidder", tr->results[i].bidder,
+ "price", tr->results[i].price);
+ GNUNET_assert (result);
+
+ GNUNET_assert (-1 !=
+ json_array_append_new (results, result));
+ }
+
+ GNUNET_assert (-1 !=
+ json_object_set_new (*output,
+ "winners",
+ results));
+
+ return GNUNET_OK;
+}
+
+
+/*
+ * @brief Parses a given json as transcript.
+ *
+ * @param[in] jtr JSON input
+ * @param[out] transcript Parsed transcript data
+ * @param[out] jresult JSON output, both, for results or errors
+ * @return GNUNET_OK on succes
+ */
+static enum GNUNET_GenericReturnValue
+parse_transcript (const json_t *jtr,
+ struct transcript *tr,
+ json_t **output)
+{
+ // TODO: json_error_t jerror;
+ // TODO: struct GNUNET_CRYPTO_EddsaSignature sig;
+
+ GNUNET_assert (jtr);
+ GNUNET_assert (tr);
+
+ {
+ json_t *auc;
+ 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_end ()
+ };
+
+ auc = json_object_get (jtr, "auction");
+ if (NULL == auc)
+ return json_error (output, "no auction found in transcript");
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (auc,
+ au_spec,
+ (const char **) &perr,
+ &eline))
+ return json_error (output, perr);
+
+ // Prices...
+ {
+ json_t *prices = json_object_get (auc, "prices");
+ size_t idx;
+ json_t *val;
+
+
+ if (! json_is_array (prices))
+ // TODO: leak!?
+ return json_error (output, "no prices found");
+
+ tr->k = json_array_size (prices);
+
+ tr->prices = GNUNET_new_array (tr->k, char *);
+ json_array_foreach (prices, idx, val)
+ {
+ if (! json_is_string (val))
+ // TODO: leak!_
+ return json_error (output, "prices not strings");
+
+ tr->prices[idx] = (char *) json_string_value (val);
+
+ // TODO: parse prices
+ }
+ }
+ }
+
+ // Bidders
+ {
+ json_t *bidders;
+
+ bidders = json_object_get (jtr, "bidders");
+ if (! bidders || ! json_is_array (bidders))
+ // TODO: leak!_
+ return json_error (output, "bidders not found");
+
+ // TODO: parse bidders as pub keys;
+ tr->n = json_array_size (bidders);
+ }
+
+
+ // Messages
+ {
+ json_t *messages;
+ size_t nm;
+
+ messages = json_object_get (jtr, "transcript");
+ if (! json_is_array (messages))
+ // TODO: leak!
+ return json_error (output, "no messages found");
+
+
+ nm = json_array_size (messages);
+
+ if (nm != (4 * tr->n))
+ // TODO: leak!
+ return json_error (output, "not the right no. of messages found");
+ }
+
+ // Winners
+ {
+ json_t *winners;
+ size_t idx;
+ json_t *val;
+
+ winners = json_object_get (jtr, "winners");
+
+ if (! json_is_array (winners))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "winners not provided, continuing without\n");
+ goto CONT;
+ }
+
+ tr->expected_len = json_array_size (winners);
+ tr->expected = GNUNET_new_array (tr->expected_len,
+ struct result);
+
+ json_array_foreach (winners, idx, val) {
+ char *error;
+
+ 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,
+ (const char**) &error,
+ NULL))
+ // TODO: leak!
+ return json_error (output, "couldn't parse winners");
+ }
+
+CONT:
+ }
+ return json_result (output, tr);
+}
+
+
/**
* @brief implements the TALER_Extension.disable interface.
*
@@ -70,7 +304,9 @@ auction_config_to_json (
const struct TALER_Extension *ext)
{
/* This extension has no configuration */
- return json_null ();
+ return GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_bool ("critical", ext->critical),
+ GNUNET_JSON_pack_string ("version", ext->version));
}
@@ -92,35 +328,67 @@ auction_load_json_config (
/**
- * @brief implements the TALER_Extension.http_post_handler
+ * @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,
+ "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
+ */
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 *result;
+
+ ret = parse_transcript (root, &tr, &result);
+
/* TODO */
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "auction_http_post_handler not implemented yet");
- return MHD_HTTP_NOT_IMPLEMENTED;
+ "auction_http_post_handler not implemented yet\n");
+
+ return TALER_MHD_reply_json_steal (connection,
+ result,
+ GNUNET_OK == ret? MHD_HTTP_OK :
+ MHD_HTTP_BAD_REQUEST);
}
/* The extension struct for auctions of brandt-style */
struct TALER_Extension TE_auction_brandt = {
- .type = 0x0815, /* TODO: where do we get this from? */
- .name = EXTENSION_NAME,
+ .type = TALER_Extension_AuctionBrandt,
+ .name = AUCTION_BRANDT,
.critical = false,
.version = "0",
.enabled = false, /* disabled per default */
+ .has_config = false, /* This extension has no configuration */
.config = NULL,
.config_json = NULL,
.disable = &auction_disable,
.test_json_config = &auction_test_json_config,
.load_json_config = &auction_load_json_config,
.config_to_json = &auction_config_to_json,
+ .http_get_handler = &auction_http_get_handler,
.http_post_handler = &auction_http_post_handler,
};
@@ -141,25 +409,31 @@ struct TALER_Extension TE_auction_brandt = {
* @return Pointer to TE_auction_brandt
*/
struct TALER_Extension *
-init (void *arg)
+libtaler_extension_auction_brandt_init (void *arg)
{
const struct GNUNET_CONFIGURATION_Handle *cfg = arg;
if (GNUNET_SYSERR ==
GNUNET_CONFIGURATION_get_value_string (cfg,
- "extension_" EXTENSION_NAME,
- "replay_program",
+ TALER_EXTENSION_SECTION_PREFIX
+ AUCTION_BRANDT,
+ "REPLAY_PROGRAM",
&replay_program))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "extension_" EXTENSION_NAME,
- "replay_program");
+ TALER_EXTENSION_SECTION_PREFIX AUCTION_BRANDT,
+ "REPLAY_PROGRAM");
return NULL;
}
+ /* TODO: check if replay_program is actually executable */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "[auction_brandt] loading... using replay_program '%s'\n",
+ replay_program);
return &TE_auction_brandt;
}
+
/**
* @brief Tear-down function for the extension.
* Will be called by GNUNET_PLUGIN_unload.
@@ -168,15 +442,14 @@ init (void *arg)
* @return null
*/
void *
-done (void *arg)
+libtaler_extension_auction_brandt_done (void *arg)
{
- auction_disable(&TE_auction_brandt);
- GNUNET_free(replay_program);
- replay_program=NULL;
+ auction_disable (&TE_auction_brandt);
+ GNUNET_free (replay_program);
+ replay_program = NULL;
- return NULL;
+ return NULL;
}
-
/* end of extension_auction_brandt.c */
diff --git a/src/include/taler_extensions.h b/src/include/taler_extensions.h
index 40b14402..1ae8ad1e 100644
--- a/src/include/taler_extensions.h
+++ b/src/include/taler_extensions.h
@@ -31,8 +31,12 @@
enum TALER_Extension_Type
{
- TALER_Extension_AgeRestriction = 0,
- TALER_Extension_MaxPredefined = 1 // Must be last of the predefined
+ TALER_Extension_Refund = 0,
+ TALER_Extension_AgeRestriction = 1,
+ TALER_Extension_P2P = 2,
+ TALER_Extension_AuctionBrandt = 3,
+ TALER_Extension_Escrow = 4,
+ TALER_Extension_MaxPredefined = 5 // Must be last of the predefined
};
@@ -59,6 +63,7 @@ struct TALER_Extension
char *version;
void *config;
bool enabled;
+ bool has_config; /* some extension might not have a configuration */
json_t *config_json;
void (*disable)(struct TALER_Extension *ext);
@@ -78,6 +83,10 @@ struct TALER_Extension
const json_t *root,
const char *const args[]);
+ MHD_RESULT (*http_get_handler)(
+ struct MHD_Connection *connection,
+ const char *const args[]);
+
};
/**
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
index add37a80..e92e4385 100644
--- a/src/lib/exchange_api_handle.c
+++ b/src/lib/exchange_api_handle.c
@@ -931,6 +931,9 @@ decode_keys_json (const json_t *resp_obj,
if (! no_extensions && ! no_signature)
{
+ GNUNET_log(GNUNET_ERROR_TYPE_INFO,
+ "DEBUG: got extensions object %s\n",
+ json_dumps(extensions, JSON_INDENT(2)));
/* 2. We have an extensions object. Verify its signature. */
EXITIF (GNUNET_OK !=
TALER_extensions_verify_json_config_signature (
diff --git a/src/testing/testing_api_cmd_batch_withdraw.c b/src/testing/testing_api_cmd_batch_withdraw.c
index 3b32b5ad..a5229ae9 100644
--- a/src/testing/testing_api_cmd_batch_withdraw.c
+++ b/src/testing/testing_api_cmd_batch_withdraw.c
@@ -490,7 +490,7 @@ TALER_TESTING_cmd_batch_withdraw (const char *label,
acp = GNUNET_new (struct TALER_AgeCommitmentProof);
hac = GNUNET_new (struct TALER_AgeCommitmentHash);
- mask = TALER_extensions_get_age_restriction_mask();
+ mask = TALER_extensions_get_age_restriction_mask ();
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&seed,
sizeof(seed));
diff --git a/src/testing/testing_api_cmd_withdraw.c b/src/testing/testing_api_cmd_withdraw.c
index 3e2f45c4..7a81d1c3 100644
--- a/src/testing/testing_api_cmd_withdraw.c
+++ b/src/testing/testing_api_cmd_withdraw.c
@@ -590,7 +590,7 @@ TALER_TESTING_cmd_withdraw_amount (const char *label,
acp = GNUNET_new (struct TALER_AgeCommitmentProof);
hac = GNUNET_new (struct TALER_AgeCommitmentHash);
- mask = TALER_extensions_get_age_restriction_mask();
+ mask = TALER_extensions_get_age_restriction_mask ();
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&seed,
sizeof(seed));