From: Schanzenbach, Martin Date: Tue, 12 Mar 2019 08:39:06 +0000 (+0100) Subject: move identity rest plugin X-Git-Tag: v0.11.1~100 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=235833535763682224d09a9b0e73fdd09657d7fc;p=oweals%2Fgnunet.git move identity rest plugin --- diff --git a/src/identity/Makefile.am b/src/identity/Makefile.am index 1f21fc65d..5c1af8e19 100644 --- a/src/identity/Makefile.am +++ b/src/identity/Makefile.am @@ -12,6 +12,12 @@ if USE_COVERAGE XLIB = -lgcov endif +if HAVE_MHD +if HAVE_JSON +REST_PLUGIN = libgnunet_plugin_rest_identity.la +endif +endif + pkgcfgdir= $(pkgdatadir)/config.d/ libexecdir= $(pkglibdir)/libexec/ @@ -20,7 +26,20 @@ pkgcfg_DATA = \ identity.conf lib_LTLIBRARIES = \ - libgnunetidentity.la + libgnunetidentity.la \ + $(REST_PLUGIN) + + +libgnunet_plugin_rest_identity_la_SOURCES = \ + plugin_rest_identity.c +libgnunet_plugin_rest_identity_la_LIBADD = \ + libgnunetidentity.la \ + $(top_builddir)/src/rest/libgnunetrest.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ + $(LTLIBINTL) -ljansson -lmicrohttpd +libgnunet_plugin_rest_identity_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + libgnunetidentity_la_SOURCES = \ identity_api.c \ diff --git a/src/identity/plugin_rest_identity.c b/src/identity/plugin_rest_identity.c new file mode 100644 index 000000000..3bfca3121 --- /dev/null +++ b/src/identity/plugin_rest_identity.c @@ -0,0 +1,1321 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2015 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 . + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/** + * @author Martin Schanzenbach + * @author Philippe Buschmann + * @file identity/plugin_rest_identity.c + * @brief GNUnet Identity REST plugin + */ + +#include "platform.h" +#include "gnunet_rest_plugin.h" +#include "gnunet_identity_service.h" +#include "gnunet_rest_lib.h" +#include "microhttpd.h" +#include + +/** + * Identity Namespace + */ +#define GNUNET_REST_API_NS_IDENTITY "/identity" + +/** + * Identity Namespace with public key specifier + */ +#define GNUNET_REST_API_NS_IDENTITY_ALL "/identity/all" + +/** + * Identity Namespace with public key specifier + */ +#define GNUNET_REST_API_NS_IDENTITY_PUBKEY "/identity/pubkey" + +/** + * Identity Namespace with public key specifier + */ +#define GNUNET_REST_API_NS_IDENTITY_NAME "/identity/name" + +/** + * Identity Subsystem Namespace + */ +#define GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM "/identity/subsystem" + +/** + * Parameter public key + */ +#define GNUNET_REST_IDENTITY_PARAM_PUBKEY "pubkey" + +/** + * Parameter subsystem + */ +#define GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM "subsystem" + +/** + * Parameter name + */ +#define GNUNET_REST_IDENTITY_PARAM_NAME "name" + +/** + * Parameter new name + */ +#define GNUNET_REST_IDENTITY_PARAM_NEWNAME "newname" + +/** + * Error message Unknown Error + */ +#define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error" + +/** + * Error message No identity found + */ +#define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found" + +/** + * Error message Missing identity name + */ +#define GNUNET_REST_IDENTITY_MISSING_NAME "Missing identity name" + +/** + * Error message Missing identity name + */ +#define GNUNET_REST_IDENTITY_MISSING_PUBKEY "Missing identity public key" + +/** + * Error message No data + */ +#define GNUNET_REST_ERROR_NO_DATA "No data" + +/** + * Error message Data invalid + */ +#define GNUNET_REST_ERROR_DATA_INVALID "Data invalid" + +/** + * 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; + +/** + * @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 +{ + /** + * 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; + + + /** + * Ego list + */ + struct EgoEntry *ego_head; + + /** + * Ego list + */ + struct EgoEntry *ego_tail; + + /** + * The processing state + */ + int state; + + /** + * Handle to Identity service. + */ + struct GNUNET_IDENTITY_Handle *identity_handle; + + /** + * IDENTITY Operation + */ + struct GNUNET_IDENTITY_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; + +}; + +/** + * Cleanup lookup handle + * @param handle Handle to clean up + */ +static void +cleanup_handle (void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct EgoEntry *ego_tmp; + + 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); + if (NULL != handle->identity_handle) + GNUNET_IDENTITY_disconnect (handle->identity_handle); + + for (ego_entry = handle->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(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_IDENTITY_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); + handle->proc (handle->proc_cls, resp, handle->response_code); + json_decref(json_error); + GNUNET_free(response); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + + +/** + * Get EgoEntry from list with either a public key or a name + * If public key and name are not NULL, it returns the public key result first + * + * @param handle the RequestHandle + * @param pubkey the public key of an identity (only one can be NULL) + * @param name the name of an identity (only one can be NULL) + * @return EgoEntry or NULL if not found + */ +struct EgoEntry* +get_egoentry(struct RequestHandle *handle, char* pubkey, char *name) +{ + struct EgoEntry *ego_entry; + if (NULL != pubkey) + { + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + { + if (0 != strcasecmp (pubkey, ego_entry->keystring)) + continue; + return ego_entry; + } + } + if (NULL != name) + { + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + { + if (0 != strcasecmp (name, ego_entry->identifier)) + continue; + return ego_entry; + } + } + return NULL; +} + + +/** + * Callback for GET Request with subsystem + * + * @param cls the RequestHandle + * @param ego the Ego found + * @param ctx the context + * @param name the id of the ego + */ +static void +ego_get_for_subsystem (void *cls, + struct GNUNET_IDENTITY_Ego *ego, + void **ctx, + const char *name) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + struct GNUNET_CRYPTO_EcdsaPublicKey public_key; + json_t *json_root; + char *result_str; + char *public_key_string; + + if(NULL == ego) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + GNUNET_IDENTITY_ego_get_public_key(ego,&public_key); + public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string(&public_key); + + // create json with subsystem identity + json_root = json_object (); + json_object_set_new (json_root, + GNUNET_REST_IDENTITY_PARAM_PUBKEY, + json_string(public_key_string)); + json_object_set_new (json_root, + GNUNET_REST_IDENTITY_PARAM_NAME, + json_string(name)); + + result_str = json_dumps (json_root, 0); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); + resp = GNUNET_REST_create_response (result_str); + + json_decref (json_root); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free(result_str); + GNUNET_free(public_key_string); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + +/** + * Handle identity GET request for subsystem + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_get_subsystem (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + char *subsystem; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url)) + { + handle->emsg = GNUNET_strdup("Missing subsystem name"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + subsystem = &handle->url[strlen ( + GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) + 1]; + //requested default identity of subsystem + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsystem); + + handle->op = GNUNET_IDENTITY_get (handle->identity_handle, + subsystem, + &ego_get_for_subsystem, + handle); + + if (NULL == handle->op) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } +} + + +/** + * Handle identity GET request - responds with all identities + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_get_all (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct MHD_Response *resp; + json_t *json_root; + json_t *json_ego; + char *result_str; + + json_root = json_array (); + //Return ego/egos + for (ego_entry = handle->ego_head; + NULL != ego_entry; ego_entry = ego_entry->next) + { + json_ego = json_object (); + json_object_set_new (json_ego, + GNUNET_REST_IDENTITY_PARAM_PUBKEY, + json_string (ego_entry->keystring)); + json_object_set_new (json_ego, + GNUNET_REST_IDENTITY_PARAM_NAME, + json_string (ego_entry->identifier)); + json_array_append (json_root, json_ego); + json_decref (json_ego); + } + + if ((size_t) 0 == json_array_size (json_root)) + { + json_decref (json_root); + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + result_str = json_dumps (json_root, 0); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); + resp = GNUNET_REST_create_response (result_str); + + json_decref (json_root); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free(result_str); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + +/** + * Responds with the ego_entry identity + * + * @param handle the struct RequestHandle + * @param ego_entry the struct EgoEntry for the response + */ +void +ego_get_response (struct RequestHandle *handle, struct EgoEntry *ego_entry) +{ + struct MHD_Response *resp; + json_t *json_ego; + char *result_str; + + json_ego = json_object (); + json_object_set_new (json_ego, + GNUNET_REST_IDENTITY_PARAM_PUBKEY, + json_string (ego_entry->keystring)); + json_object_set_new (json_ego, + GNUNET_REST_IDENTITY_PARAM_NAME, + json_string (ego_entry->identifier)); + + result_str = json_dumps (json_ego, 0); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); + resp = GNUNET_REST_create_response (result_str); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + + json_decref (json_ego); + GNUNET_free(result_str); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + +/** + * Handle identity GET request with a public key + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *keystring; + + keystring = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1]; + ego_entry = get_egoentry(handle, keystring, NULL); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + ego_get_response(handle, ego_entry); +} + +/** + * Handle identity GET request with a name + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_get_name (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *egoname; + + egoname = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + egoname = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1]; + ego_entry = get_egoentry(handle, NULL, egoname); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + ego_get_response(handle, ego_entry); +} + + +/** + * Processing finished + * + * @param cls request handle + * @param emsg error message + */ +static void +do_finished (void *cls, const char *emsg) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + + handle->op = NULL; + if (NULL != emsg) + { + handle->emsg = GNUNET_strdup(emsg); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (0 == handle->response_code) + { + handle->response_code = MHD_HTTP_NO_CONTENT; + } + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, handle->response_code); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + +/** + * Processing edit ego with EgoEntry ego_entry + * + * @param handle the struct RequestHandle + * @param ego_entry the struct EgoEntry we want to edit + */ +void +ego_edit (struct RequestHandle *handle, struct EgoEntry *ego_entry) +{ + struct EgoEntry *ego_entry_tmp; + struct MHD_Response *resp; + json_t *data_js; + json_error_t err; + char *newname; + char term_data[handle->data_size + 1]; + int json_state; + + //if no data + if (0 >= handle->data_size) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + //if not json + term_data[handle->data_size] = '\0'; + GNUNET_memcpy(term_data, handle->data, handle->data_size); + data_js = json_loads (term_data,JSON_DECODE_ANY,&err); + + if (NULL == data_js) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + newname = NULL; + //NEW NAME + json_state = 0; + json_state = json_unpack(data_js, + "{s:s!}", + GNUNET_REST_IDENTITY_PARAM_NEWNAME, + &newname); + //Change name with pubkey or name identifier + if (0 != json_state) + { + + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + if (NULL == newname) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + if (0 >= strlen (newname)) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + ego_entry_tmp = get_egoentry (handle, NULL, newname); + if (NULL != ego_entry_tmp) + { + //Ego with same name not allowed (even if its the ego we change) + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); + json_decref (data_js); + return; + } + handle->op = GNUNET_IDENTITY_rename (handle->identity_handle, + ego_entry->identifier, + newname, + &do_finished, + handle); + if (NULL == handle->op) + { + handle->emsg = GNUNET_strdup("Rename failed"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + json_decref (data_js); + return; + +} + + +/** + * Handle identity PUT request with public key + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_edit_pubkey (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *keystring; + + keystring = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1]; + ego_entry = get_egoentry(handle, keystring, NULL); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + ego_edit(handle,ego_entry); +} + +/** + * Handle identity PUT request with name + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *name; + + name = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1]; + ego_entry = get_egoentry(handle, NULL, name); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + ego_edit(handle,ego_entry); +} + +/** + * Handle identity subsystem PUT request with name + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_edit_subsystem (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + json_t *data_js; + json_error_t err; + char *newsubsys; + char *name; + char term_data[handle->data_size + 1]; + int json_state; + + name = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM)+1]; + ego_entry = get_egoentry(handle, NULL, name); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + //if no data + if (0 >= handle->data_size) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + //if not json + term_data[handle->data_size] = '\0'; + GNUNET_memcpy(term_data, handle->data, handle->data_size); + data_js = json_loads (term_data,JSON_DECODE_ANY,&err); + + if (NULL == data_js) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + newsubsys = NULL; + //SUBSYSTEM + json_state = 0; + json_state = json_unpack(data_js, + "{s:s!}", + GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM, + &newsubsys); + //Change subsystem with pubkey or name identifier + if (0 != json_state) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + if (NULL == newsubsys) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + if (0 >= strlen (newsubsys)) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + handle->response_code = MHD_HTTP_NO_CONTENT; + handle->op = GNUNET_IDENTITY_set (handle->identity_handle, + newsubsys, + ego_entry->ego, + &do_finished, + handle); + if (NULL == handle->op) + { + handle->emsg = GNUNET_strdup("Setting subsystem failed"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + json_decref (data_js); + return; + +} + +/** + * Handle identity POST request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_create (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct MHD_Response *resp; + json_t *data_js; + json_error_t err; + char* egoname; + int json_unpack_state; + char term_data[handle->data_size + 1]; + + if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url)) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + if (0 >= handle->data_size) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + term_data[handle->data_size] = '\0'; + GNUNET_memcpy(term_data, handle->data, handle->data_size); + data_js = json_loads (term_data, + JSON_DECODE_ANY, + &err); + if (NULL == data_js) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + json_unpack_state = 0; + json_unpack_state = json_unpack(data_js, + "{s:s!}", + GNUNET_REST_IDENTITY_PARAM_NAME, + &egoname); + if (0 != json_unpack_state) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + if (NULL == egoname) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + if (0 >= strlen (egoname)) + { + json_decref (data_js); + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + GNUNET_STRINGS_utf8_tolower(egoname, egoname); + for (ego_entry = handle->ego_head; + NULL != ego_entry; ego_entry = ego_entry->next) + { + if (0 == strcasecmp (egoname, ego_entry->identifier)) + { + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); + json_decref (data_js); + return; + } + } + handle->name = GNUNET_strdup(egoname); + json_decref (data_js); + handle->response_code = MHD_HTTP_CREATED; + handle->op = GNUNET_IDENTITY_create (handle->identity_handle, handle->name, + &do_finished, handle); +} + +/** + * Handle identity DELETE request with public key + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *keystring; + + keystring = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1]; + ego_entry = get_egoentry(handle, keystring, NULL); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + handle->response_code = MHD_HTTP_NO_CONTENT; + handle->op = GNUNET_IDENTITY_delete (handle->identity_handle, + ego_entry->identifier, + &do_finished, + handle); +} + + +/** + * Handle identity DELETE request with name + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *name; + + name = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1]; + ego_entry = get_egoentry(handle, NULL, name); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + handle->response_code = MHD_HTTP_NO_CONTENT; + handle->op = GNUNET_IDENTITY_delete (handle->identity_handle, + ego_entry->identifier, + &do_finished, + 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; +} + +/** + * Handle rest request + * + * @param handle the request handle + */ +static void +init_cont (struct RequestHandle *handle) +{ + struct GNUNET_REST_RequestHandlerError err; + static const struct GNUNET_REST_RequestHandler handlers[] = { + { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ALL, &ego_get_all }, + { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_get_pubkey }, + { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_get_name }, + { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_get_subsystem }, + { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_edit_pubkey }, + { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_edit_name }, + { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_edit_subsystem }, + { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create }, + { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_delete_pubkey }, + { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_delete_name }, + { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont }, + GNUNET_REST_HANDLER_END + }; + + if (GNUNET_NO + == GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, + handle)) + { + handle->response_code = err.error_code; + GNUNET_SCHEDULER_add_now (&do_error, handle); + } +} + +/** + * 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 +init_egos (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx, + const char *identifier) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct GNUNET_CRYPTO_EcdsaPublicKey pk; + + if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state)) + { + handle->state = ID_REST_STATE_POST_INIT; + init_cont (handle); + return; + } + if (ID_REST_STATE_INIT == handle->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; + GNUNET_asprintf (&ego_entry->identifier, "%s", identifier); + GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail, + ego_entry); + } +} + +/** + * 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 void +rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle, + GNUNET_REST_ResultProcessor proc, void *proc_cls) +{ + struct RequestHandle *handle = GNUNET_new(struct RequestHandle); + + 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'; + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); + + handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &init_egos, handle); + + handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout, + &do_error, handle); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); +} + +/** + * Entry point for the plugin. + * + * @param cls Config info + * @return NULL on error, otherwise the plugin context + */ +void * +libgnunet_plugin_rest_identity_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_IDENTITY; + api->process_request = &rest_process_request; + GNUNET_asprintf (&allow_methods, "%s, %s, %s, %s, %s", + MHD_HTTP_METHOD_GET, + MHD_HTTP_METHOD_POST, + MHD_HTTP_METHOD_PUT, + MHD_HTTP_METHOD_DELETE, + MHD_HTTP_METHOD_OPTIONS); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Identity 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_identity_done (void *cls) +{ + struct GNUNET_REST_Plugin *api = cls; + struct Plugin *plugin = api->cls; + plugin->cfg = NULL; + + GNUNET_free_non_null(allow_methods); + GNUNET_free(api); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n"); + return NULL; +} + +/* end of plugin_rest_identity.c */ + diff --git a/src/rest-plugins/Makefile.am b/src/rest-plugins/Makefile.am index cec9348a6..e99d88676 100644 --- a/src/rest-plugins/Makefile.am +++ b/src/rest-plugins/Makefile.am @@ -20,7 +20,6 @@ endif plugin_LTLIBRARIES = \ libgnunet_plugin_rest_copying.la \ libgnunet_plugin_rest_peerinfo.la \ - libgnunet_plugin_rest_identity.la \ libgnunet_plugin_rest_namestore.la @@ -57,16 +56,6 @@ libgnunet_plugin_rest_peerinfo_la_LIBADD = \ libgnunet_plugin_rest_peerinfo_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) -libgnunet_plugin_rest_identity_la_SOURCES = \ - plugin_rest_identity.c -libgnunet_plugin_rest_identity_la_LIBADD = \ - $(top_builddir)/src/identity/libgnunetidentity.la \ - $(top_builddir)/src/rest/libgnunetrest.la \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -ljansson -lmicrohttpd -libgnunet_plugin_rest_identity_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - libgnunet_plugin_rest_namestore_la_SOURCES = \ diff --git a/src/rest-plugins/plugin_rest_identity.c b/src/rest-plugins/plugin_rest_identity.c deleted file mode 100644 index 3bfca3121..000000000 --- a/src/rest-plugins/plugin_rest_identity.c +++ /dev/null @@ -1,1321 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 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 . - - SPDX-License-Identifier: AGPL3.0-or-later - */ -/** - * @author Martin Schanzenbach - * @author Philippe Buschmann - * @file identity/plugin_rest_identity.c - * @brief GNUnet Identity REST plugin - */ - -#include "platform.h" -#include "gnunet_rest_plugin.h" -#include "gnunet_identity_service.h" -#include "gnunet_rest_lib.h" -#include "microhttpd.h" -#include - -/** - * Identity Namespace - */ -#define GNUNET_REST_API_NS_IDENTITY "/identity" - -/** - * Identity Namespace with public key specifier - */ -#define GNUNET_REST_API_NS_IDENTITY_ALL "/identity/all" - -/** - * Identity Namespace with public key specifier - */ -#define GNUNET_REST_API_NS_IDENTITY_PUBKEY "/identity/pubkey" - -/** - * Identity Namespace with public key specifier - */ -#define GNUNET_REST_API_NS_IDENTITY_NAME "/identity/name" - -/** - * Identity Subsystem Namespace - */ -#define GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM "/identity/subsystem" - -/** - * Parameter public key - */ -#define GNUNET_REST_IDENTITY_PARAM_PUBKEY "pubkey" - -/** - * Parameter subsystem - */ -#define GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM "subsystem" - -/** - * Parameter name - */ -#define GNUNET_REST_IDENTITY_PARAM_NAME "name" - -/** - * Parameter new name - */ -#define GNUNET_REST_IDENTITY_PARAM_NEWNAME "newname" - -/** - * Error message Unknown Error - */ -#define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error" - -/** - * Error message No identity found - */ -#define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found" - -/** - * Error message Missing identity name - */ -#define GNUNET_REST_IDENTITY_MISSING_NAME "Missing identity name" - -/** - * Error message Missing identity name - */ -#define GNUNET_REST_IDENTITY_MISSING_PUBKEY "Missing identity public key" - -/** - * Error message No data - */ -#define GNUNET_REST_ERROR_NO_DATA "No data" - -/** - * Error message Data invalid - */ -#define GNUNET_REST_ERROR_DATA_INVALID "Data invalid" - -/** - * 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; - -/** - * @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 -{ - /** - * 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; - - - /** - * Ego list - */ - struct EgoEntry *ego_head; - - /** - * Ego list - */ - struct EgoEntry *ego_tail; - - /** - * The processing state - */ - int state; - - /** - * Handle to Identity service. - */ - struct GNUNET_IDENTITY_Handle *identity_handle; - - /** - * IDENTITY Operation - */ - struct GNUNET_IDENTITY_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; - -}; - -/** - * Cleanup lookup handle - * @param handle Handle to clean up - */ -static void -cleanup_handle (void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct EgoEntry *ego_tmp; - - 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); - if (NULL != handle->identity_handle) - GNUNET_IDENTITY_disconnect (handle->identity_handle); - - for (ego_entry = handle->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(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_IDENTITY_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); - handle->proc (handle->proc_cls, resp, handle->response_code); - json_decref(json_error); - GNUNET_free(response); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - - -/** - * Get EgoEntry from list with either a public key or a name - * If public key and name are not NULL, it returns the public key result first - * - * @param handle the RequestHandle - * @param pubkey the public key of an identity (only one can be NULL) - * @param name the name of an identity (only one can be NULL) - * @return EgoEntry or NULL if not found - */ -struct EgoEntry* -get_egoentry(struct RequestHandle *handle, char* pubkey, char *name) -{ - struct EgoEntry *ego_entry; - if (NULL != pubkey) - { - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (0 != strcasecmp (pubkey, ego_entry->keystring)) - continue; - return ego_entry; - } - } - if (NULL != name) - { - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (0 != strcasecmp (name, ego_entry->identifier)) - continue; - return ego_entry; - } - } - return NULL; -} - - -/** - * Callback for GET Request with subsystem - * - * @param cls the RequestHandle - * @param ego the Ego found - * @param ctx the context - * @param name the id of the ego - */ -static void -ego_get_for_subsystem (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *name) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - struct GNUNET_CRYPTO_EcdsaPublicKey public_key; - json_t *json_root; - char *result_str; - char *public_key_string; - - if(NULL == ego) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - GNUNET_IDENTITY_ego_get_public_key(ego,&public_key); - public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string(&public_key); - - // create json with subsystem identity - json_root = json_object (); - json_object_set_new (json_root, - GNUNET_REST_IDENTITY_PARAM_PUBKEY, - json_string(public_key_string)); - json_object_set_new (json_root, - GNUNET_REST_IDENTITY_PARAM_NAME, - json_string(name)); - - result_str = json_dumps (json_root, 0); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - - json_decref (json_root); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free(result_str); - GNUNET_free(public_key_string); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - -/** - * Handle identity GET request for subsystem - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_get_subsystem (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - char *subsystem; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url)) - { - handle->emsg = GNUNET_strdup("Missing subsystem name"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - subsystem = &handle->url[strlen ( - GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) + 1]; - //requested default identity of subsystem - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsystem); - - handle->op = GNUNET_IDENTITY_get (handle->identity_handle, - subsystem, - &ego_get_for_subsystem, - handle); - - if (NULL == handle->op) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } -} - - -/** - * Handle identity GET request - responds with all identities - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_get_all (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct MHD_Response *resp; - json_t *json_root; - json_t *json_ego; - char *result_str; - - json_root = json_array (); - //Return ego/egos - for (ego_entry = handle->ego_head; - NULL != ego_entry; ego_entry = ego_entry->next) - { - json_ego = json_object (); - json_object_set_new (json_ego, - GNUNET_REST_IDENTITY_PARAM_PUBKEY, - json_string (ego_entry->keystring)); - json_object_set_new (json_ego, - GNUNET_REST_IDENTITY_PARAM_NAME, - json_string (ego_entry->identifier)); - json_array_append (json_root, json_ego); - json_decref (json_ego); - } - - if ((size_t) 0 == json_array_size (json_root)) - { - json_decref (json_root); - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - result_str = json_dumps (json_root, 0); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - - json_decref (json_root); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free(result_str); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Responds with the ego_entry identity - * - * @param handle the struct RequestHandle - * @param ego_entry the struct EgoEntry for the response - */ -void -ego_get_response (struct RequestHandle *handle, struct EgoEntry *ego_entry) -{ - struct MHD_Response *resp; - json_t *json_ego; - char *result_str; - - json_ego = json_object (); - json_object_set_new (json_ego, - GNUNET_REST_IDENTITY_PARAM_PUBKEY, - json_string (ego_entry->keystring)); - json_object_set_new (json_ego, - GNUNET_REST_IDENTITY_PARAM_NAME, - json_string (ego_entry->identifier)); - - result_str = json_dumps (json_ego, 0); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - - json_decref (json_ego); - GNUNET_free(result_str); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Handle identity GET request with a public key - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *keystring; - - keystring = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1]; - ego_entry = get_egoentry(handle, keystring, NULL); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - ego_get_response(handle, ego_entry); -} - -/** - * Handle identity GET request with a name - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_get_name (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *egoname; - - egoname = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - egoname = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1]; - ego_entry = get_egoentry(handle, NULL, egoname); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - ego_get_response(handle, ego_entry); -} - - -/** - * Processing finished - * - * @param cls request handle - * @param emsg error message - */ -static void -do_finished (void *cls, const char *emsg) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - handle->op = NULL; - if (NULL != emsg) - { - handle->emsg = GNUNET_strdup(emsg); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (0 == handle->response_code) - { - handle->response_code = MHD_HTTP_NO_CONTENT; - } - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, handle->response_code); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Processing edit ego with EgoEntry ego_entry - * - * @param handle the struct RequestHandle - * @param ego_entry the struct EgoEntry we want to edit - */ -void -ego_edit (struct RequestHandle *handle, struct EgoEntry *ego_entry) -{ - struct EgoEntry *ego_entry_tmp; - struct MHD_Response *resp; - json_t *data_js; - json_error_t err; - char *newname; - char term_data[handle->data_size + 1]; - int json_state; - - //if no data - if (0 >= handle->data_size) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - //if not json - term_data[handle->data_size] = '\0'; - GNUNET_memcpy(term_data, handle->data, handle->data_size); - data_js = json_loads (term_data,JSON_DECODE_ANY,&err); - - if (NULL == data_js) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - newname = NULL; - //NEW NAME - json_state = 0; - json_state = json_unpack(data_js, - "{s:s!}", - GNUNET_REST_IDENTITY_PARAM_NEWNAME, - &newname); - //Change name with pubkey or name identifier - if (0 != json_state) - { - - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - if (NULL == newname) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - if (0 >= strlen (newname)) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - ego_entry_tmp = get_egoentry (handle, NULL, newname); - if (NULL != ego_entry_tmp) - { - //Ego with same name not allowed (even if its the ego we change) - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); - json_decref (data_js); - return; - } - handle->op = GNUNET_IDENTITY_rename (handle->identity_handle, - ego_entry->identifier, - newname, - &do_finished, - handle); - if (NULL == handle->op) - { - handle->emsg = GNUNET_strdup("Rename failed"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - json_decref (data_js); - return; - -} - - -/** - * Handle identity PUT request with public key - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_edit_pubkey (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *keystring; - - keystring = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1]; - ego_entry = get_egoentry(handle, keystring, NULL); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - ego_edit(handle,ego_entry); -} - -/** - * Handle identity PUT request with name - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *name; - - name = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1]; - ego_entry = get_egoentry(handle, NULL, name); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - ego_edit(handle,ego_entry); -} - -/** - * Handle identity subsystem PUT request with name - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_edit_subsystem (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - json_t *data_js; - json_error_t err; - char *newsubsys; - char *name; - char term_data[handle->data_size + 1]; - int json_state; - - name = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM)+1]; - ego_entry = get_egoentry(handle, NULL, name); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - //if no data - if (0 >= handle->data_size) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - //if not json - term_data[handle->data_size] = '\0'; - GNUNET_memcpy(term_data, handle->data, handle->data_size); - data_js = json_loads (term_data,JSON_DECODE_ANY,&err); - - if (NULL == data_js) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - newsubsys = NULL; - //SUBSYSTEM - json_state = 0; - json_state = json_unpack(data_js, - "{s:s!}", - GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM, - &newsubsys); - //Change subsystem with pubkey or name identifier - if (0 != json_state) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - if (NULL == newsubsys) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - if (0 >= strlen (newsubsys)) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - handle->response_code = MHD_HTTP_NO_CONTENT; - handle->op = GNUNET_IDENTITY_set (handle->identity_handle, - newsubsys, - ego_entry->ego, - &do_finished, - handle); - if (NULL == handle->op) - { - handle->emsg = GNUNET_strdup("Setting subsystem failed"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - json_decref (data_js); - return; - -} - -/** - * Handle identity POST request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_create (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct MHD_Response *resp; - json_t *data_js; - json_error_t err; - char* egoname; - int json_unpack_state; - char term_data[handle->data_size + 1]; - - if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url)) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - if (0 >= handle->data_size) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - term_data[handle->data_size] = '\0'; - GNUNET_memcpy(term_data, handle->data, handle->data_size); - data_js = json_loads (term_data, - JSON_DECODE_ANY, - &err); - if (NULL == data_js) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - json_unpack_state = 0; - json_unpack_state = json_unpack(data_js, - "{s:s!}", - GNUNET_REST_IDENTITY_PARAM_NAME, - &egoname); - if (0 != json_unpack_state) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - if (NULL == egoname) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - if (0 >= strlen (egoname)) - { - json_decref (data_js); - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - GNUNET_STRINGS_utf8_tolower(egoname, egoname); - for (ego_entry = handle->ego_head; - NULL != ego_entry; ego_entry = ego_entry->next) - { - if (0 == strcasecmp (egoname, ego_entry->identifier)) - { - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); - json_decref (data_js); - return; - } - } - handle->name = GNUNET_strdup(egoname); - json_decref (data_js); - handle->response_code = MHD_HTTP_CREATED; - handle->op = GNUNET_IDENTITY_create (handle->identity_handle, handle->name, - &do_finished, handle); -} - -/** - * Handle identity DELETE request with public key - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *keystring; - - keystring = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1]; - ego_entry = get_egoentry(handle, keystring, NULL); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - handle->response_code = MHD_HTTP_NO_CONTENT; - handle->op = GNUNET_IDENTITY_delete (handle->identity_handle, - ego_entry->identifier, - &do_finished, - handle); -} - - -/** - * Handle identity DELETE request with name - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *name; - - name = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1]; - ego_entry = get_egoentry(handle, NULL, name); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - handle->response_code = MHD_HTTP_NO_CONTENT; - handle->op = GNUNET_IDENTITY_delete (handle->identity_handle, - ego_entry->identifier, - &do_finished, - 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; -} - -/** - * Handle rest request - * - * @param handle the request handle - */ -static void -init_cont (struct RequestHandle *handle) -{ - struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = { - { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ALL, &ego_get_all }, - { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_get_pubkey }, - { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_get_name }, - { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_get_subsystem }, - { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_edit_pubkey }, - { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_edit_name }, - { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_edit_subsystem }, - { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create }, - { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_delete_pubkey }, - { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_delete_name }, - { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont }, - GNUNET_REST_HANDLER_END - }; - - if (GNUNET_NO - == GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, - handle)) - { - handle->response_code = err.error_code; - GNUNET_SCHEDULER_add_now (&do_error, handle); - } -} - -/** - * 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 -init_egos (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx, - const char *identifier) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct GNUNET_CRYPTO_EcdsaPublicKey pk; - - if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state)) - { - handle->state = ID_REST_STATE_POST_INIT; - init_cont (handle); - return; - } - if (ID_REST_STATE_INIT == handle->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; - GNUNET_asprintf (&ego_entry->identifier, "%s", identifier); - GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail, - ego_entry); - } -} - -/** - * 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 void -rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, void *proc_cls) -{ - struct RequestHandle *handle = GNUNET_new(struct RequestHandle); - - 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'; - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); - - handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &init_egos, handle); - - handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout, - &do_error, handle); - - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); -} - -/** - * Entry point for the plugin. - * - * @param cls Config info - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_rest_identity_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_IDENTITY; - api->process_request = &rest_process_request; - GNUNET_asprintf (&allow_methods, "%s, %s, %s, %s, %s", - MHD_HTTP_METHOD_GET, - MHD_HTTP_METHOD_POST, - MHD_HTTP_METHOD_PUT, - MHD_HTTP_METHOD_DELETE, - MHD_HTTP_METHOD_OPTIONS); - - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Identity 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_identity_done (void *cls) -{ - struct GNUNET_REST_Plugin *api = cls; - struct Plugin *plugin = api->cls; - plugin->cfg = NULL; - - GNUNET_free_non_null(allow_methods); - GNUNET_free(api); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n"); - return NULL; -} - -/* end of plugin_rest_identity.c */ -