summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjospaeth <spaethj@in.tum.de>2020-09-06 15:04:50 +0200
committerjospaeth <spaethj@in.tum.de>2020-09-06 15:04:50 +0200
commit03b7dd8d216b6d14cf0abd66b23f01b2ea94fab1 (patch)
tree1df4db57e573ba300add2d5af8f804c444342268
parentf05dbd1b35316d10629247f7c0398f8ec2c70d93 (diff)
add escrow REST plugin
-rw-r--r--src/escrow/Makefile.am17
-rw-r--r--src/escrow/escrow.h2
-rw-r--r--src/escrow/gnunet-escrow.c2
-rw-r--r--src/escrow/plugin_escrow_gns.c2
-rw-r--r--src/escrow/plugin_escrow_plaintext.c2
-rw-r--r--src/escrow/plugin_rest_escrow.c1252
-rw-r--r--src/include/gnunet_escrow_lib.h4
7 files changed, 1274 insertions, 7 deletions
diff --git a/src/escrow/Makefile.am b/src/escrow/Makefile.am
index 70dbfc2e9..36bb027ab 100644
--- a/src/escrow/Makefile.am
+++ b/src/escrow/Makefile.am
@@ -26,11 +26,26 @@ plugin_LTLIBRARIES = \
libgnunet_plugin_escrow_plaintext.la \
libgnunet_plugin_escrow_gns.la \
libgnunet_plugin_escrow_anastasis.la \
- libgnunet_plugin_gnsrecord_escrow.la
+ libgnunet_plugin_gnsrecord_escrow.la \
+ libgnunet_plugin_rest_escrow.la
bin_PROGRAMS = \
gnunet-escrow
+
+libgnunet_plugin_rest_escrow_la_SOURCES = \
+ plugin_rest_escrow.c
+libgnunet_plugin_rest_escrow_la_LIBADD = \
+ libgnunetescrow.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
+ $(top_builddir)/src/rest/libgnunetrest.la \
+ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
+ $(LTLIBINTL) -ljansson $(MHD_LIBS)
+libgnunet_plugin_rest_escrow_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+libgnunet_plugin_rest_escrow_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
+
+
libgnunetescrow_la_SOURCES = \
escrow_api.c \
escrow.h
diff --git a/src/escrow/escrow.h b/src/escrow/escrow.h
index a9e6e99e1..8fc9123c1 100644
--- a/src/escrow/escrow.h
+++ b/src/escrow/escrow.h
@@ -203,7 +203,7 @@ struct ESCROW_Plugin_EgoContinuationWrapper
/**
* The restored ego
*/
- const struct GNUNET_IDENTITY_Ego *ego;
+ struct GNUNET_IDENTITY_Ego *ego;
/**
* The unique ID of the respective ESCROW_Operation
diff --git a/src/escrow/gnunet-escrow.c b/src/escrow/gnunet-escrow.c
index 9fa219d2f..c3ca3aa9e 100644
--- a/src/escrow/gnunet-escrow.c
+++ b/src/escrow/gnunet-escrow.c
@@ -235,7 +235,7 @@ verify_cb (void *cls,
static void
get_cb (void *cls,
- const struct GNUNET_IDENTITY_Ego *ego,
+ struct GNUNET_IDENTITY_Ego *ego,
const char *emsg)
{
escrow_op = NULL;
diff --git a/src/escrow/plugin_escrow_gns.c b/src/escrow/plugin_escrow_gns.c
index 96a7252ec..908c7bb44 100644
--- a/src/escrow/plugin_escrow_gns.c
+++ b/src/escrow/plugin_escrow_gns.c
@@ -1507,7 +1507,7 @@ verify_gns_key_escrow (struct GNUNET_ESCROW_Handle *h,
void
-ego_created (const struct GNUNET_IDENTITY_Ego *ego)
+ego_created (struct GNUNET_IDENTITY_Ego *ego)
{
struct ESCROW_PluginOperationWrapper *curr;
struct ESCROW_GnsPluginOperation *curr_p_op;
diff --git a/src/escrow/plugin_escrow_plaintext.c b/src/escrow/plugin_escrow_plaintext.c
index 41523a906..39f605262 100644
--- a/src/escrow/plugin_escrow_plaintext.c
+++ b/src/escrow/plugin_escrow_plaintext.c
@@ -291,7 +291,7 @@ verify_plaintext_key_escrow (struct GNUNET_ESCROW_Handle *h,
static void
-ego_created (const struct GNUNET_IDENTITY_Ego *ego)
+ego_created (struct GNUNET_IDENTITY_Ego *ego)
{
struct ESCROW_PluginOperationWrapper *curr;
struct ESCROW_PlaintextPluginOperation *curr_p_op;
diff --git a/src/escrow/plugin_rest_escrow.c b/src/escrow/plugin_rest_escrow.c
new file mode 100644
index 000000000..12d48faf5
--- /dev/null
+++ b/src/escrow/plugin_rest_escrow.c
@@ -0,0 +1,1252 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ GNUnet 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
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ SPDX-License-Identifier: AGPL3.0-or-later
+ */
+/**
+ * @author Johannes Sp├Ąth
+ * @file escrow/plugin_rest_escrow.c
+ * @brief GNUnet Escrow REST plugin
+ */
+
+#include "platform.h"
+#include "gnunet_rest_plugin.h"
+#include "gnunet_escrow_lib.h"
+#include "gnunet_identity_service.h"
+#include "gnunet_rest_lib.h"
+#include "microhttpd.h"
+#include <jansson.h>
+
+/**
+ * Escrow Namespace
+ */
+#define GNUNET_REST_API_NS_ESCROW "/escrow"
+
+/**
+ * Escrow Put Namespace
+ */
+#define GNUNET_REST_API_NS_ESCROW_PUT "/escrow/put"
+
+/**
+ * Escrow Get Namespace
+ */
+#define GNUNET_REST_API_NS_ESCROW_GET "/escrow/get"
+
+/**
+ * Escrow Verify Namespace
+ */
+#define GNUNET_REST_API_NS_ESCROW_VERIFY "/escrow/verify"
+
+/**
+ * Escrow Status Namespace
+ */
+#define GNUNET_REST_API_NS_ESCROW_STATUS "/escrow/status"
+
+/**
+ * Error message Unknown Error
+ */
+#define GNUNET_REST_ESCROW_ERROR_UNKNOWN "Unknown Error"
+
+/**
+ * Error message Missing identity name
+ */
+#define GNUNET_REST_ESCROW_MISSING_NAME "Missing identity name"
+
+/**
+ * Error message Missing escrow anchor
+ */
+#define GNUNET_REST_ESCROW_MISSING_ANCHOR "Missing escrow anchor"
+
+/**
+ * Error message Identity not found
+ */
+#define GNUNET_REST_ESCROW_ID_NOT_FOUND "Identity not found"
+
+/**
+ * Error message Method not found
+ */
+#define GNUNET_REST_ESCROW_METHOD_NOT_FOUND "Method not found"
+
+/**
+ * Error message Escrow failed
+ */
+#define GNUNET_REST_ESCROW_ESCROW_FAILED "Escrow failed"
+
+/**
+ * Error message Restoration failed
+ */
+#define GNUNET_REST_ESCROW_RESTORE_FAILED "Restoration failed"
+
+/**
+ * Error message Got invalid status
+ */
+#define GNUNET_REST_ESCROW_INVALID_STATUS "Got invalid status"
+
+/**
+ * Error message No data
+ */
+#define GNUNET_REST_ERROR_NO_DATA "No data"
+
+/**
+ * Error message Data invalid
+ */
+#define GNUNET_REST_ERROR_DATA_INVALID "Data invalid"
+
+/**
+ * Error message Failed to parse anchor
+ */
+#define GNUNET_REST_ESCROW_ANCHOR_ERROR "Failed to parse anchor"
+
+/**
+ * Parameter anchor
+ */
+#define GNUNET_REST_ESCROW_PARAM_ANCHOR "anchor"
+
+/**
+ * Parameter user-secret
+ */
+#define GNUNET_REST_ESCROW_PARAM_USER_SECRET "user-secret"
+
+/**
+ * Parameter pubkey
+ */
+#define GNUNET_REST_ESCROW_PARAM_PUBKEY "pubkey"
+
+/**
+ * Parameter name
+ */
+#define GNUNET_REST_ESCROW_PARAM_NAME "name"
+
+/**
+ * Parameter verification-result
+ */
+#define GNUNET_REST_ESCROW_PARAM_VERIFICATION_RESULT "verification-result"
+
+/**
+ * Parameter last-method
+ */
+#define GNUNET_REST_ESCROW_PARAM_LAST_METHOD "last-method"
+
+/**
+ * Parameter last-successful-verification
+ */
+#define GNUNET_REST_ESCROW_PARAM_LAST_VERIF "last-successful-verification"
+
+/**
+ * Parameter next-recommended-verification
+ */
+#define GNUNET_REST_ESCROW_PARAM_NEXT_VERIF "next-recommended-verification"
+
+/**
+ * State while collecting all egos
+ */
+#define ID_REST_STATE_INIT 0
+
+/**
+ * Done collecting egos
+ */
+#define ID_REST_STATE_POST_INIT 1
+
+/**
+ * The configuration handle
+ */
+const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * HTTP methods allows for this plugin
+ */
+static char *allow_methods;
+
+/**
+ * Ego list
+ */
+static struct EgoEntry *ego_head;
+
+/**
+ * Ego list
+ */
+static struct EgoEntry *ego_tail;
+
+/**
+ * The processing state
+ */
+static int state;
+
+/**
+ * Handle to the identity service
+ */
+static struct GNUNET_IDENTITY_Handle *identity_handle;
+
+/**
+ * Handle to the escrow component
+ */
+static struct GNUNET_ESCROW_Handle *escrow_handle;
+
+/**
+ * @brief struct returned by the initialization function of the plugin
+ */
+struct Plugin
+{
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+};
+
+/**
+ * The ego list
+ */
+struct EgoEntry
+{
+ /**
+ * DLL
+ */
+ struct EgoEntry *next;
+
+ /**
+ * DLL
+ */
+ struct EgoEntry *prev;
+
+ /**
+ * Ego Identifier
+ */
+ char *identifier;
+
+ /**
+ * Public key string
+ */
+ char *keystring;
+
+ /**
+ * The Ego
+ */
+ struct GNUNET_IDENTITY_Ego *ego;
+};
+
+/**
+ * The request handle
+ */
+struct RequestHandle
+{
+ /**
+ * DLL
+ */
+ struct RequestHandle *next;
+
+ /**
+ * DLL
+ */
+ struct RequestHandle *prev;
+
+ /**
+ * The data from the REST request
+ */
+ const char *data;
+
+ /**
+ * The name to look up
+ */
+ char *name;
+
+ /**
+ * the length of the REST data
+ */
+ size_t data_size;
+
+ /**
+ * ESCROW Operation
+ */
+ struct GNUNET_ESCROW_Operation *op;
+
+ /**
+ * Rest connection
+ */
+ struct GNUNET_REST_RequestHandle *rest_handle;
+
+ /**
+ * Desired timeout for the lookup (default is no timeout).
+ */
+ struct GNUNET_TIME_Relative timeout;
+
+ /**
+ * ID of a task associated with the resolution process.
+ */
+ struct GNUNET_SCHEDULER_Task *timeout_task;
+
+ /**
+ * The plugin result processor
+ */
+ GNUNET_REST_ResultProcessor proc;
+
+ /**
+ * The closure of the result processor
+ */
+ void *proc_cls;
+
+ /**
+ * The url
+ */
+ char *url;
+
+ /**
+ * Error response message
+ */
+ char *emsg;
+
+ /**
+ * Response code
+ */
+ int response_code;
+
+ /**
+ * Response object
+ */
+ json_t *resp_object;
+};
+
+/**
+ * DLL
+ */
+static struct RequestHandle *requests_head;
+
+/**
+ * DLL
+ */
+static struct RequestHandle *requests_tail;
+
+/**
+ * Cleanup lookup handle
+ * @param handle Handle to clean up
+ */
+static void
+cleanup_handle (void *cls)
+{
+ struct RequestHandle *handle = cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
+ if (NULL != handle->timeout_task)
+ {
+ GNUNET_SCHEDULER_cancel (handle->timeout_task);
+ handle->timeout_task = NULL;
+ }
+
+ if (NULL != handle->url)
+ GNUNET_free (handle->url);
+ if (NULL != handle->emsg)
+ GNUNET_free (handle->emsg);
+ if (NULL != handle->name)
+ GNUNET_free (handle->name);
+ GNUNET_CONTAINER_DLL_remove (requests_head,
+ requests_tail,
+ handle);
+ GNUNET_free (handle);
+}
+
+
+/**
+ * Task run on errors. Reports an error and cleans up everything.
+ *
+ * @param cls the `struct RequestHandle`
+ */
+static void
+do_error (void *cls)
+{
+ struct RequestHandle *handle = cls;
+ struct MHD_Response *resp;
+ json_t *json_error = json_object ();
+ char *response;
+
+ if (NULL == handle->emsg)
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_ERROR_UNKNOWN);
+
+ json_object_set_new (json_error, "error", json_string (handle->emsg));
+
+ if (0 == handle->response_code)
+ handle->response_code = MHD_HTTP_OK;
+ response = json_dumps (json_error, 0);
+ resp = GNUNET_REST_create_response (response);
+ MHD_add_response_header (resp, "Content-Type", "application/json");
+ handle->proc (handle->proc_cls, resp, handle->response_code);
+ json_decref (json_error);
+ GNUNET_free (response);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
+}
+
+
+static enum GNUNET_ESCROW_Key_Escrow_Method
+determine_escrow_method (struct GNUNET_CONTAINER_MultiHashMap *url_param_map)
+{
+ struct GNUNET_HashCode method_key;
+ char *method_string;
+ enum GNUNET_ESCROW_Key_Escrow_Method method;
+
+ GNUNET_CRYPTO_hash ("method", strlen ("method"), &method_key);
+ method_string = GNUNET_CONTAINER_multihashmap_get (url_param_map,
+ &method_key);
+ // default method is plaintext
+ if (NULL == method_string)
+ method = GNUNET_ESCROW_KEY_PLAINTEXT;
+ else
+ method = GNUNET_ESCROW_method_string_to_number (method_string);
+
+ return method;
+}
+
+
+static char *
+get_user_secret_from_payload (struct RequestHandle *handle)
+{
+ json_t *json_data;
+ json_error_t err;
+ char *user_secret, *user_secret_cpy;
+ int json_unpack_state;
+ char term_data[handle->data_size + 1];
+
+ if (0 >= handle->data_size)
+ {
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return NULL;
+ }
+
+ term_data[handle->data_size] = '\0';
+ GNUNET_memcpy (term_data, handle->data, handle->data_size);
+ json_data = json_loads (term_data, JSON_DECODE_ANY, &err);
+ if (NULL == json_data)
+ {
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (json_data);
+ return NULL;
+ }
+
+ json_unpack_state = 0;
+ json_unpack_state =
+ json_unpack (json_data, "{s:s}",
+ GNUNET_REST_ESCROW_PARAM_USER_SECRET, &user_secret);
+ if (0 != json_unpack_state)
+ {
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (json_data);
+ return NULL;
+ }
+
+ if (NULL == user_secret)
+ {
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (json_data);
+ return NULL;
+ }
+ if (0 >= strlen (user_secret))
+ {
+ json_decref (json_data);
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return NULL;
+ }
+
+ user_secret_cpy = GNUNET_strdup (user_secret);
+ json_decref (json_data);
+
+ return user_secret_cpy;
+}
+
+
+static void
+escrow_finished (void *cls,
+ struct GNUNET_ESCROW_Anchor *anchor,
+ const char *emsg)
+{
+ struct RequestHandle *handle = cls;
+ struct MHD_Response *resp;
+ json_t *json_anchor;
+ char *anchor_string, *result_string;
+
+ if (NULL == anchor)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Failed to escrow ego.\n");
+ handle->response_code = MHD_HTTP_NO_CONTENT;
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_ESCROW_FAILED);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+ anchor_string = GNUNET_ESCROW_anchor_data_to_string (anchor);
+ json_anchor = json_object ();
+ json_object_set_new (json_anchor,
+ GNUNET_REST_ESCROW_PARAM_ANCHOR,
+ json_string (anchor_string));
+
+ result_string = json_dumps (json_anchor, 0);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_string);
+ resp = GNUNET_REST_create_response (result_string);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+ MHD_add_response_header (resp, "Content-Type", "application/json");
+
+ json_decref (json_anchor);
+ GNUNET_free (result_string);
+ GNUNET_free (anchor_string);
+
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
+}
+
+
+/**
+ * Respond to PUT (start_escrow) request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+static void
+escrow_identity (struct GNUNET_REST_RequestHandle *con_handle,
+ const char *url,
+ void *cls)
+{
+ struct RequestHandle *handle = cls;
+ struct EgoEntry *ego_entry;
+ char *identity, *userSecret;
+ enum GNUNET_ESCROW_Key_Escrow_Method method;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Putting %s into escrow.\n",
+ handle->url);
+
+ if (strlen (GNUNET_REST_API_NS_ESCROW_PUT) >= strlen (handle->url))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
+ handle->response_code = MHD_HTTP_NOT_FOUND;
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_MISSING_NAME);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ identity = handle->url + strlen (GNUNET_REST_API_NS_ESCROW_PUT) + 1;
+
+ for (ego_entry = ego_head; NULL != ego_entry;
+ ego_entry = ego_entry->next)
+ if (0 == strcmp (identity, ego_entry->identifier))
+ break;
+
+ if (NULL == ego_entry)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Identity %s not found.\n",
+ identity);
+ handle->response_code = MHD_HTTP_NOT_FOUND;
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_ID_NOT_FOUND);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+ /* determine method */
+ method = determine_escrow_method (handle->rest_handle->url_param_map);
+ if (GNUNET_ESCROW_KEY_NONE == method)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Method not found.\n");
+ handle->response_code = MHD_HTTP_NOT_FOUND;
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_METHOD_NOT_FOUND);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+ /* get user secret */
+ if (GNUNET_ESCROW_KEY_PLAINTEXT != method)
+ {
+ userSecret = get_user_secret_from_payload (handle);
+ if (NULL == userSecret)
+ // get_user_secret_from_payload () already cleaned up
+ return;
+ }
+ else
+ userSecret = NULL;
+
+ handle->op = GNUNET_ESCROW_put (escrow_handle,
+ ego_entry->ego,
+ userSecret,
+ method,
+ &escrow_finished,
+ handle);
+
+ if (NULL != userSecret)
+ GNUNET_free (userSecret);
+}
+
+
+static struct GNUNET_ESCROW_Anchor *
+get_anchor_from_payload (struct RequestHandle *handle)
+{
+ json_t *json_data;
+ json_error_t err;
+ char *anchor_string;
+ int json_unpack_state;
+ char term_data[handle->data_size + 1];
+ struct GNUNET_ESCROW_Anchor *anchor;
+
+ if (0 >= handle->data_size)
+ {
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return NULL;
+ }
+
+ term_data[handle->data_size] = '\0';
+ GNUNET_memcpy (term_data, handle->data, handle->data_size);
+ json_data = json_loads (term_data, JSON_DECODE_ANY, &err);
+ if (NULL == json_data)
+ {
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (json_data);
+ return NULL;
+ }
+
+ json_unpack_state = 0;
+ json_unpack_state =
+ json_unpack (json_data, "{s:s}",
+ GNUNET_REST_ESCROW_PARAM_ANCHOR, &anchor_string);
+ if (0 != json_unpack_state)
+ {
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (json_data);
+ return NULL;
+ }
+
+ if (NULL == anchor_string)
+ {
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (json_data);
+ return NULL;
+ }
+ if (0 >= strlen (anchor_string))
+ {
+ json_decref (json_data);
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return NULL;
+ }
+
+ json_decref (json_data);
+
+ anchor = GNUNET_ESCROW_anchor_string_to_data (anchor_string);
+ if (NULL == anchor)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Failed to parse anchor: %s.\n", anchor_string);
+ handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_ANCHOR_ERROR);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return NULL;
+ }
+
+ return anchor;
+}
+
+
+static void
+restore_finished (void *cls,
+ struct GNUNET_IDENTITY_Ego *ego,
+ const char *emsg)
+{
+ struct RequestHandle *handle = cls;
+ struct EgoEntry *ego_entry;
+ struct MHD_Response *resp;
+ struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub;
+ json_t *json_ego;
+ char *keystring, *result_string;
+
+ if (NULL == ego)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Failed to restore ego.\n");
+ handle->response_code = MHD_HTTP_NO_CONTENT;
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_RESTORE_FAILED);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+ GNUNET_IDENTITY_ego_get_public_key (ego, &ego_pub);
+ keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ego_pub);
+
+ for (ego_entry = ego_head; NULL != ego_entry;
+ ego_entry = ego_entry->next)
+ if (0 == strcmp (keystring, ego_entry->keystring))
+ break;
+
+ if (NULL == ego_entry)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Identity not found despite successful restoration.\n");
+ handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_ID_NOT_FOUND);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ GNUNET_free (keystring);
+ return;
+ }
+
+ json_ego = json_object ();
+ json_object_set_new (json_ego,
+ GNUNET_REST_ESCROW_PARAM_NAME,
+ json_string (ego_entry->identifier));
+ json_object_set_new (json_ego,
+ GNUNET_REST_ESCROW_PARAM_PUBKEY,
+ json_string (ego_entry->keystring));
+
+ result_string = json_dumps (json_ego, 0);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_string);
+ resp = GNUNET_REST_create_response (result_string);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+ MHD_add_response_header (resp, "Content-Type", "application/json");
+
+ json_decref (json_ego);
+ GNUNET_free (result_string);
+ GNUNET_free (keystring);
+
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
+}
+
+
+/**
+ * Respond to GET (restore) request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+static void
+get_escrowed_identity (struct GNUNET_REST_RequestHandle *con_handle,
+ const char *url,
+ void *cls)
+{
+ struct RequestHandle *handle = cls;
+ struct GNUNET_ESCROW_Anchor *anchor;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Getting %s from escrow.\n",
+ handle->url);
+
+ /* get anchor */
+ anchor = get_anchor_from_payload (handle);
+ if (NULL == anchor)
+ // get_anchor_from_payload () already cleaned up
+ return;
+
+ handle->op = GNUNET_ESCROW_get (escrow_handle,
+ anchor,
+ &restore_finished,
+ handle);
+}
+
+
+static void
+verify_finished (void *cls,
+ int verificationResult,
+ const char *emsg)
+{
+ struct RequestHandle *handle = cls;
+ struct MHD_Response *resp;
+ json_t *json_verif;
+ const char *verif_string;
+ char *result_string;
+
+ switch (verificationResult)
+ {
+ case GNUNET_ESCROW_VALID:
+ verif_string = "valid";
+ break;
+ case GNUNET_ESCROW_INVALID:
+ verif_string = "invalid";
+ break;
+ case GNUNET_ESCROW_SHARES_MISSING:
+ verif_string = "shares_missing";
+ break;
+ default:
+ verif_string = "unknown";
+ }
+
+ json_verif = json_object ();
+ json_object_set_new (json_verif,
+ GNUNET_REST_ESCROW_PARAM_VERIFICATION_RESULT,
+ json_string (verif_string));
+
+ result_string = json_dumps (json_verif, 0);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_string);
+ resp = GNUNET_REST_create_response (result_string);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+ MHD_add_response_header (resp, "Content-Type", "application/json");
+
+ json_decref (json_verif);
+ GNUNET_free (result_string);
+
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
+}
+
+
+/**
+ * Respond to VERIFY request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+static void
+verify_escrow (struct GNUNET_REST_RequestHandle *con_handle,
+ const char *url,
+ void *cls)
+{
+ struct RequestHandle *handle = cls;
+ struct EgoEntry *ego_entry;
+ struct GNUNET_ESCROW_Anchor *anchor;
+ char *identity;
+ enum GNUNET_ESCROW_Key_Escrow_Method method;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Verifying escrow of %s.\n",
+ handle->url);
+
+ if (strlen (GNUNET_REST_API_NS_ESCROW_VERIFY) >= strlen (handle->url))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
+ handle->response_code = MHD_HTTP_NOT_FOUND;
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_MISSING_NAME);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ identity = handle->url + strlen (GNUNET_REST_API_NS_ESCROW_VERIFY) + 1;
+
+ for (ego_entry = ego_head; NULL != ego_entry;
+ ego_entry = ego_entry->next)
+ if (0 == strcmp (identity, ego_entry->identifier))
+ break;
+
+ if (NULL == ego_entry)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Identity %s not found.\n",
+ identity);
+ handle->response_code = MHD_HTTP_NOT_FOUND;
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_ID_NOT_FOUND);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+ /* determine method */
+ method = determine_escrow_method (handle->rest_handle->url_param_map);
+ if (GNUNET_ESCROW_KEY_NONE == method)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Method not found.\n");
+ handle->response_code = MHD_HTTP_NOT_FOUND;
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_METHOD_NOT_FOUND);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+ /* get anchor */
+ anchor = get_anchor_from_payload (handle);
+ if (NULL == anchor)
+ // get_anchor_from_payload () already cleaned up
+ return;
+
+ handle->op = GNUNET_ESCROW_verify (escrow_handle,
+ ego_entry->ego,
+ anchor,
+ method,
+ &verify_finished,
+ handle);
+}
+
+
+/**
+ * Respond to STATUS request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+static void
+get_escrow_status (struct GNUNET_REST_RequestHandle *con_handle,
+ const char *url,
+ void *cls)
+{
+ struct RequestHandle *handle = cls;
+ struct EgoEntry *ego_entry;
+ struct GNUNET_ESCROW_Status *status;
+ struct MHD_Response *resp;
+ char *identity;
+ enum GNUNET_ESCROW_Key_Escrow_Method method;
+ json_t *json_status;
+ char *result_string;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Getting escrow status of %s.\n",
+ handle->url);
+
+ if (strlen (GNUNET_REST_API_NS_ESCROW_STATUS) >= strlen (handle->url))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
+ handle->response_code = MHD_HTTP_NOT_FOUND;
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_MISSING_NAME);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ identity = handle->url + strlen (GNUNET_REST_API_NS_ESCROW_STATUS) + 1;
+
+ for (ego_entry = ego_head; NULL != ego_entry;
+ ego_entry = ego_entry->next)
+ if (0 == strcmp (identity, ego_entry->identifier))
+ break;
+
+ if (NULL == ego_entry)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Identity %s not found.\n",
+ identity);
+ handle->response_code = MHD_HTTP_NOT_FOUND;
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_ID_NOT_FOUND);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+ /* determine method */
+ method = determine_escrow_method (handle->rest_handle->url_param_map);
+ if (GNUNET_ESCROW_KEY_NONE == method)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Method not found.\n");
+ handle->response_code = MHD_HTTP_NOT_FOUND;
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_METHOD_NOT_FOUND);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+ status = GNUNET_ESCROW_get_status (escrow_handle,
+ ego_entry->ego,
+ method);
+
+ if (NULL == status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got invalid status.\n");
+ handle->response_code = MHD_HTTP_NO_CONTENT;
+ handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_INVALID_STATUS);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+ /* create and send response */
+ json_status = json_object ();
+ if (GNUNET_ESCROW_KEY_NONE == status->last_method)
+ json_object_set_new (json_status,
+ GNUNET_REST_ESCROW_PARAM_LAST_METHOD,
+ json_string ("none"));
+ else
+ {
+ json_object_set_new (json_status,
+ GNUNET_REST_ESCROW_PARAM_LAST_METHOD,
+ json_string (
+ GNUNET_ESCROW_method_number_to_string (status->last_method)));
+ json_object_set_new (json_status,
+ GNUNET_REST_ESCROW_PARAM_LAST_VERIF,
+ json_string (
+ GNUNET_STRINGS_absolute_time_to_string (
+ status->last_successful_verification_time)));
+ json_object_set_new (json_status,
+ GNUNET_REST_ESCROW_PARAM_NEXT_VERIF,
+ json_string (
+ GNUNET_STRINGS_absolute_time_to_string (
+ status->next_recommended_verification_time)));
+ }
+
+ result_string = json_dumps (json_status, 0);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_string);
+ resp = GNUNET_REST_create_response (result_string);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+ MHD_add_response_header (resp, "Content-Type", "application/json");
+
+ json_decref (json_status);
+ GNUNET_free (result_string);
+
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
+}
+
+
+/**
+ * Respond to OPTIONS request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+static void
+options_cont (struct GNUNET_REST_RequestHandle *con_handle,
+ const char *url,
+ void *cls)
+{
+ struct MHD_Response *resp;
+ struct RequestHandle *handle = cls;
+
+ // For now, independent of path return all options
+ resp = GNUNET_REST_create_response (NULL);
+ MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
+ return;
+}
+
+
+/**
+ * If listing is enabled, prints information about the egos.
+ *
+ * This function is initially called for all egos and then again
+ * whenever a ego's identifier changes or if it is deleted. At the
+ * end of the initial pass over all egos, the function is once called
+ * with 'NULL' for 'ego'. That does NOT mean that the callback won't
+ * be invoked in the future or that there was an error.
+ *
+ * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
+ * this function is only called ONCE, and 'NULL' being passed in
+ * 'ego' does indicate an error (i.e. name is taken or no default
+ * value is known). If 'ego' is non-NULL and if '*ctx'
+ * is set in those callbacks, the value WILL be passed to a subsequent
+ * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
+ * that one was not NULL).
+ *
+ * When an identity is renamed, this function is called with the
+ * (known) ego but the NEW identifier.
+ *
+ * When an identity is deleted, this function is called with the
+ * (known) ego and "NULL" for the 'identifier'. In this case,
+ * the 'ego' is henceforth invalid (and the 'ctx' should also be
+ * cleaned up).
+ *
+ * @param cls closure
+ * @param ego ego handle
+ * @param ctx context for application to store data for this ego
+ * (during the lifetime of this process, initially NULL)
+ * @param identifier identifier assigned by the user for this ego,
+ * NULL if the user just deleted the ego and it
+ * must thus no longer be used
+ */
+static void
+list_ego (void *cls,
+ struct GNUNET_IDENTITY_Ego *ego,
+ void **ctx,
+ const char *identifier)
+{
+ struct EgoEntry *ego_entry;
+ struct GNUNET_CRYPTO_EcdsaPublicKey pk;
+
+ if ((NULL == ego) && (ID_REST_STATE_INIT == state))
+ {
+ state = ID_REST_STATE_POST_INIT;
+ return;
+ }
+ if (ID_REST_STATE_INIT == state)
+ {
+ ego_entry = GNUNET_new (struct EgoEntry);
+ GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
+ ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
+ ego_entry->ego = ego;
+ ego_entry->identifier = GNUNET_strdup (identifier);
+ GNUNET_CONTAINER_DLL_insert_tail (ego_head,
+ ego_tail,
+ ego_entry);
+ }
+ /* Ego renamed or added */
+ if (identifier != NULL)
+ {
+ for (ego_entry = ego_head; NULL != ego_entry;
+ ego_entry = ego_entry->next)
+ {
+ if (ego_entry->ego == ego)
+ {
+ /* Rename */
+ GNUNET_free (ego_entry->identifier);
+ ego_entry->identifier = GNUNET_strdup (identifier);
+ break;
+ }
+ }
+ if (NULL == ego_entry)
+ {
+ /* Add */
+ ego_entry = GNUNET_new (struct EgoEntry);
+ GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
+ ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
+ ego_entry->ego = ego;
+ ego_entry->identifier = GNUNET_strdup (identifier);
+ GNUNET_CONTAINER_DLL_insert_tail (ego_head,
+ ego_tail,
+ ego_entry);
+ }
+ }
+ else
+ {
+ /* Delete */
+ for (ego_entry = ego_head; NULL != ego_entry;
+ ego_entry = ego_entry->next)
+ {
+ if (ego_entry->ego == ego)
+ break;
+ }
+ if (NULL == ego_entry)
+ return; /* Not found */
+
+ GNUNET_CONTAINER_DLL_remove (ego_head,
+ ego_tail,
+ ego_entry);
+ GNUNET_free (ego_entry->identifier);
+ GNUNET_free (ego_entry->keystring);
+ GNUNET_free (ego_entry);
+ return;
+ }
+
+}
+
+
+/**
+ * Function processing the REST call
+ *
+ * @param method HTTP method
+ * @param url URL of the HTTP request
+ * @param data body of the HTTP request (optional)
+ * @param data_size length of the body
+ * @param proc callback function for the result
+ * @param proc_cls closure for callback function
+ * @return GNUNET_OK if request accepted
+ */
+static enum GNUNET_GenericReturnValue
+rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
+ GNUNET_REST_ResultProcessor proc,
+ void *proc_cls)
+{
+ struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
+ struct GNUNET_REST_RequestHandlerError err;
+ static const struct GNUNET_REST_RequestHandler handlers[] =
+ { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_ESCROW_VERIFY, &verify_escrow },
+ { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_ESCROW_STATUS, &get_escrow_status },
+ { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_ESCROW_GET, &get_escrowed_identity },
+ { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_ESCROW_PUT, &escrow_identity },
+ { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_ESCROW, &options_cont },
+ GNUNET_REST_HANDLER_END };
+
+
+ handle->response_code = 0;
+ handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+ handle->proc_cls = proc_cls;
+ handle->proc = proc;
+ handle->rest_handle = rest_handle;
+ handle->data = rest_handle->data;
+ handle->data_size = rest_handle->data_size;
+
+ handle->url = GNUNET_strdup (rest_handle->url);
+ if (handle->url[strlen (handle->url) - 1] == '/')
+ handle->url[strlen (handle->url) - 1] = '\0';
+ handle->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_error, handle);
+ GNUNET_CONTAINER_DLL_insert (requests_head,
+ requests_tail,
+ handle);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
+ if (GNUNET_NO ==
+ GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
+ {
+ cleanup_handle (handle);
+ return GNUNET_NO;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
+ return GNUNET_YES;
+}
+
+
+/**
+ * Entry point for the plugin.
+ *
+ * @param cls Config info
+ * @return NULL on error, otherwise the plugin context
+ */
+void *
+libgnunet_plugin_rest_escrow_init (void *cls)
+{
+ static struct Plugin plugin;
+ struct GNUNET_REST_Plugin *api;
+
+ cfg = cls;
+ if (NULL != plugin.cfg)
+ return NULL; /* can only initialize once! */
+ memset (&plugin, 0, sizeof(struct Plugin));
+ plugin.cfg = cfg;
+ api = GNUNET_new (struct GNUNET_REST_Plugin);
+ api->cls = &plugin;
+ api->name = GNUNET_REST_API_NS_ESCROW;
+ api->process_request = &rest_process_request;
+ GNUNET_asprintf (&allow_methods,
+ "%s, %s, %s",
+ MHD_HTTP_METHOD_GET,
+ MHD_HTTP_METHOD_POST,
+ MHD_HTTP_METHOD_OPTIONS);
+ state = ID_REST_STATE_INIT;
+ identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, NULL);
+ escrow_handle = GNUNET_ESCROW_init (cfg);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Escrow REST API initialized\n"));
+ return api;
+}
+
+
+/**
+ * Exit point from the plugin.
+ *
+ * @param cls the plugin context (as returned by "init")
+ * @return always NULL
+ */
+void *
+libgnunet_plugin_rest_escrow_done (void *cls)
+{
+ struct GNUNET_REST_Plugin *api = cls;
+ struct Plugin *plugin = api->cls;
+ struct EgoEntry *ego_entry;
+ struct EgoEntry *ego_tmp;
+
+ plugin->cfg = NULL;
+ while (NULL != requests_head)
+ cleanup_handle (requests_head);
+ if (NULL != escrow_handle)
+ GNUNET_ESCROW_fini (escrow_handle);
+ if (NULL != identity_handle)
+ GNUNET_IDENTITY_disconnect (identity_handle);
+ for (ego_entry = ego_head; NULL != ego_entry;)
+ {
+ ego_tmp = ego_entry;
+ ego_entry = ego_entry->next;
+ GNUNET_free (ego_tmp->identifier);
+ GNUNET_free (ego_tmp->keystring);
+ GNUNET_free (ego_tmp);
+ }
+
+ GNUNET_free (allow_methods);
+ GNUNET_free (api);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Escrow REST plugin is finished\n");
+ return NULL;
+}
+
+
+/* end of plugin_rest_escrow.c */
diff --git a/src/include/gnunet_escrow_lib.h b/src/include/gnunet_escrow_lib.h
index 864d6356d..546fdfeb9 100644
--- a/src/include/gnunet_escrow_lib.h
+++ b/src/include/gnunet_escrow_lib.h
@@ -120,7 +120,7 @@ typedef void (*GNUNET_ESCROW_IdentityInitContinuation) ();
* because of an escrow GET operation.
*/
typedef void (*GNUNET_ESCROW_EgoCreateContinuation) (
- const struct GNUNET_IDENTITY_Ego *ego);
+ struct GNUNET_IDENTITY_Ego *ego);
/**
* Continuation for PUT operations.
@@ -143,7 +143,7 @@ typedef void (*GNUNET_ESCROW_AnchorContinuation) (
*/
typedef void (*GNUNET_ESCROW_EgoContinuation) (
void *cls,
- const struct GNUNET_IDENTITY_Ego *ego,
+ struct GNUNET_IDENTITY_Ego *ego,
const char *emsg);
/**