From a31198a7231bc072f428eccb57a45db5dfc65105 Mon Sep 17 00:00:00 2001 From: "Schanzenbach, Martin" Date: Thu, 27 Sep 2018 19:31:50 +0200 Subject: bye bye jsonapi --- src/rest-plugins/Makefile.am | 21 +- src/rest-plugins/json_reclaim.c | 242 +++++++ src/rest-plugins/json_reclaim.h | 46 ++ src/rest-plugins/plugin_rest_reclaim.c | 1097 ++++++++++++++++++++++++++++++++ 4 files changed, 1402 insertions(+), 4 deletions(-) create mode 100644 src/rest-plugins/json_reclaim.c create mode 100644 src/rest-plugins/json_reclaim.h create mode 100644 src/rest-plugins/plugin_rest_reclaim.c (limited to 'src/rest-plugins') diff --git a/src/rest-plugins/Makefile.am b/src/rest-plugins/Makefile.am index 484dceaba..61cd7955d 100644 --- a/src/rest-plugins/Makefile.am +++ b/src/rest-plugins/Makefile.am @@ -25,9 +25,25 @@ plugin_LTLIBRARIES = \ libgnunet_plugin_rest_gns.la \ libgnunet_plugin_rest_credential.la if HAVE_ABE -plugin_LTLIBRARIES += libgnunet_plugin_rest_openid_connect.la +plugin_LTLIBRARIES += libgnunet_plugin_rest_openid_connect.la \ + libgnunet_plugin_rest_reclaim.la endif +libgnunet_plugin_rest_reclaim_la_SOURCES = \ + plugin_rest_reclaim.c \ + json_reclaim.c +libgnunet_plugin_rest_reclaim_la_LIBADD = \ + $(top_builddir)/src/identity/libgnunetidentity.la \ + $(top_builddir)/src/reclaim/libgnunetreclaim.la \ + $(top_builddir)/src/rest/libgnunetrest.la \ + $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ + $(LTLIBINTL) -ljansson -lmicrohttpd +libgnunet_plugin_rest_reclaim_la_LDFLAGS = \ + i$(GN_PLUGIN_LDFLAGS) + + libgnunet_plugin_rest_credential_la_SOURCES = \ plugin_rest_credential.c libgnunet_plugin_rest_credential_la_LIBADD = \ @@ -41,9 +57,6 @@ libgnunet_plugin_rest_credential_la_LIBADD = \ libgnunet_plugin_rest_credential_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) - - - libgnunet_plugin_rest_copying_la_SOURCES = \ plugin_rest_copying.c libgnunet_plugin_rest_copying_la_LIBADD = \ diff --git a/src/rest-plugins/json_reclaim.c b/src/rest-plugins/json_reclaim.c new file mode 100644 index 000000000..c0cce3be5 --- /dev/null +++ b/src/rest-plugins/json_reclaim.c @@ -0,0 +1,242 @@ +/* + This file is part of GNUnet. + Copyright (C) 2009-2018 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 . +*/ + +/** + * @file rest-plugins/json_reclaim.c + * @brief JSON handling of reclaim data + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_json_lib.h" +#include "gnunet_reclaim_service.h" +#include "gnunet_reclaim_attribute_lib.h" + +/** + * Parse given JSON object to a claim + * + * @param cls closure, NULL + * @param root the json object representing data + * @param spec where to write the data + * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error + */ +static int +parse_attr (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr; + const char* name_str; + const char* val_str; + const char* type_str; + const char* exp_str; + char *data; + int unpack_state; + uint32_t type; + size_t data_size; + + GNUNET_assert(NULL != root); + + if(!json_is_object(root)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error json is not array nor object!\n"); + return GNUNET_SYSERR; + } + //interpret single attribute + unpack_state = json_unpack(root, + "{s:s, s:s, s:s, s:s!}", + "name", &name_str, + "type", &type_str, + "value", &val_str, + "exp", &exp_str); + if (0 != unpack_state) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Error json object has a wrong format!\n"); + return GNUNET_SYSERR; + } + type = GNUNET_RECLAIM_ATTRIBUTE_typename_to_number (type_str); + if (GNUNET_SYSERR == (GNUNET_RECLAIM_ATTRIBUTE_string_to_value (type, + val_str, + (void**)&data, + &data_size))) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Attribute value invalid!\n"); + return GNUNET_SYSERR; + } + attr = GNUNET_RECLAIM_ATTRIBUTE_claim_new (name_str, + type, + data, + data_size); + *(struct GNUNET_RECLAIM_ATTRIBUTE_Claim **) spec->ptr = attr; + return GNUNET_OK; +} + +/** + * Cleanup data left from parsing RSA public key. + * + * @param cls closure, NULL + * @param[out] spec where to free the data + */ +static void +clean_attr (void *cls, struct GNUNET_JSON_Specification *spec) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_Claim **attr; + attr = (struct GNUNET_RECLAIM_ATTRIBUTE_Claim **) spec->ptr; + if (NULL != *attr) + { + GNUNET_free(*attr); + *attr = NULL; + } +} + +/** + * JSON Specification for Reclaim claims. + * + * @param ticket struct of GNUNET_RECLAIM_ATTRIBUTE_Claim to fill + * @return JSON Specification + */ +struct GNUNET_JSON_Specification +GNUNET_RECLAIM_JSON_spec_claim (struct GNUNET_RECLAIM_ATTRIBUTE_Claim **attr) +{ + struct GNUNET_JSON_Specification ret = { + .parser = &parse_attr, + .cleaner = &clean_attr, + .cls = NULL, + .field = NULL, + .ptr = attr, + .ptr_size = 0, + .size_ptr = NULL + }; + *attr = NULL; + return ret; +} +/** + * Parse given JSON object to a ticket + * + * @param cls closure, NULL + * @param root the json object representing data + * @param spec where to write the data + * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error + */ +static int +parse_ticket (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + struct GNUNET_RECLAIM_Ticket *ticket; + const char* rnd_str; + const char* aud_str; + const char* id_str; + int unpack_state; + + GNUNET_assert(NULL != root); + + if(!json_is_object(root)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error json is not array nor object!\n"); + return GNUNET_SYSERR; + } + //interpret single ticket + unpack_state = json_unpack(root, + "{s:s, s:s, s:s!}", + "rnd", &rnd_str, + "audience", &aud_str, + "identity", &id_str); + if (0 != unpack_state) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Error json object has a wrong format!\n"); + return GNUNET_SYSERR; + } + ticket = GNUNET_new (struct GNUNET_RECLAIM_Ticket); + if (GNUNET_OK != GNUNET_STRINGS_string_to_data (rnd_str, + strlen (rnd_str), + &ticket->rnd, + sizeof (uint64_t))) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,"Rnd invalid\n"); + GNUNET_free(ticket); + return GNUNET_SYSERR; + } + GNUNET_STRINGS_string_to_data (id_str, + strlen (id_str), + &ticket->identity, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,"Identity invalid\n"); + GNUNET_free(ticket); + return GNUNET_SYSERR; + } + + GNUNET_STRINGS_string_to_data (aud_str, + strlen (aud_str), + &ticket->audience, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,"Audience invalid\n"); + GNUNET_free(ticket); + return GNUNET_SYSERR; + } + + *(struct GNUNET_RECLAIM_Ticket **) spec->ptr = ticket; + return GNUNET_OK; +} + +/** + * Cleanup data left from parsing RSA public key. + * + * @param cls closure, NULL + * @param[out] spec where to free the data + */ +static void +clean_ticket (void *cls, struct GNUNET_JSON_Specification *spec) +{ + struct GNUNET_RECLAIM_Ticket **ticket; + ticket = (struct GNUNET_RECLAIM_Ticket **) spec->ptr; + if (NULL != *ticket) + { + GNUNET_free(*ticket); + *ticket = NULL; + } +} + +/** + * JSON Specification for Reclaim tickets. + * + * @param ticket struct of GNUNET_RECLAIM_Ticket to fill + * @return JSON Specification + */ +struct GNUNET_JSON_Specification +GNUNET_RECLAIM_JSON_spec_ticket (struct GNUNET_RECLAIM_Ticket **ticket) +{ + struct GNUNET_JSON_Specification ret = { + .parser = &parse_ticket, + .cleaner = &clean_ticket, + .cls = NULL, + .field = NULL, + .ptr = ticket, + .ptr_size = 0, + .size_ptr = NULL + }; + *ticket = NULL; + return ret; +} diff --git a/src/rest-plugins/json_reclaim.h b/src/rest-plugins/json_reclaim.h new file mode 100644 index 000000000..49674a173 --- /dev/null +++ b/src/rest-plugins/json_reclaim.h @@ -0,0 +1,46 @@ +/* + This file is part of GNUnet. + Copyright (C) 2009-2018 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 . +*/ + +/** + * @file rest-plugins/json_reclaim.h + * @brief JSON handling of reclaim data + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_json_lib.h" +#include "gnunet_reclaim_service.h" +#include "gnunet_reclaim_attribute_lib.h" + +/** + * JSON Specification for Reclaim claims. + * + * @param ticket struct of GNUNET_RECLAIM_ATTRIBUTE_Claim to fill + * @return JSON Specification + */ +struct GNUNET_JSON_Specification +GNUNET_RECLAIM_JSON_spec_claim (struct GNUNET_RECLAIM_ATTRIBUTE_Claim **attr); + +/** + * JSON Specification for Reclaim tickets. + * + * @param ticket struct of GNUNET_RECLAIM_Ticket to fill + * @return JSON Specification + */ +struct GNUNET_JSON_Specification +GNUNET_RECLAIM_JSON_spec_ticket (struct GNUNET_RECLAIM_Ticket **ticket); diff --git a/src/rest-plugins/plugin_rest_reclaim.c b/src/rest-plugins/plugin_rest_reclaim.c new file mode 100644 index 000000000..9115a9449 --- /dev/null +++ b/src/rest-plugins/plugin_rest_reclaim.c @@ -0,0 +1,1097 @@ +/* + 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 . + */ +/** + * @author Martin Schanzenbach + * @author Philippe Buschmann + * @file reclaim/plugin_rest_reclaim.c + * @brief GNUnet reclaim REST plugin + * + */ + +#include "platform.h" +#include "gnunet_rest_plugin.h" +#include "gnunet_identity_service.h" +#include "gnunet_gns_service.h" +#include "gnunet_gnsrecord_lib.h" +#include "gnunet_namestore_service.h" +#include "gnunet_rest_lib.h" +#include "gnunet_jsonapi_lib.h" +#include "gnunet_jsonapi_util.h" +#include "microhttpd.h" +#include +#include +#include "gnunet_signatures.h" +#include "gnunet_reclaim_attribute_lib.h" +#include "gnunet_reclaim_service.h" +#include "json_reclaim.h" + +/** + * REST root namespace + */ +#define GNUNET_REST_API_NS_RECLAIM "/reclaim" + +/** + * Attribute namespace + */ +#define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/reclaim/attributes" + +/** + * Ticket namespace + */ +#define GNUNET_REST_API_NS_IDENTITY_TICKETS "/reclaim/tickets" + +/** + * Revoke namespace + */ +#define GNUNET_REST_API_NS_IDENTITY_REVOKE "/reclaim/revoke" + +/** + * Revoke namespace + */ +#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/reclaim/consume" + +/** + * 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; +}; + + +struct RequestHandle +{ + /** + * Ego list + */ + struct EgoEntry *ego_head; + + /** + * Ego list + */ + struct EgoEntry *ego_tail; + + /** + * Selected ego + */ + struct EgoEntry *ego_entry; + + /** + * Pointer to ego private key + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; + + /** + * The processing state + */ + int state; + + /** + * Handle to Identity service. + */ + struct GNUNET_IDENTITY_Handle *identity_handle; + + /** + * Rest connection + */ + struct GNUNET_REST_RequestHandle *rest_handle; + + /** + * Handle to NAMESTORE + */ + struct GNUNET_NAMESTORE_Handle *namestore_handle; + + /** + * Iterator for NAMESTORE + */ + struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it; + + /** + * Attribute claim list + */ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list; + + /** + * IDENTITY Operation + */ + struct GNUNET_IDENTITY_Operation *op; + + /** + * Identity Provider + */ + struct GNUNET_RECLAIM_Handle *idp; + + /** + * Idp Operation + */ + struct GNUNET_RECLAIM_Operation *idp_op; + + /** + * Attribute iterator + */ + struct GNUNET_RECLAIM_AttributeIterator *attr_it; + + /** + * Ticket iterator + */ + struct GNUNET_RECLAIM_TicketIterator *ticket_it; + + /** + * A ticket + */ + struct GNUNET_RECLAIM_Ticket ticket; + + /** + * 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; + + /** + * Reponse code + */ + int response_code; + + /** + * Response object + */ + json_t *resp_object; + +}; + +/** + * Cleanup lookup handle + * @param handle Handle to clean up + */ +static void +cleanup_handle (struct RequestHandle *handle) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp; + struct EgoEntry *ego_entry; + struct EgoEntry *ego_tmp; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up\n"); + if (NULL != handle->resp_object) + json_decref (handle->resp_object); + if (NULL != handle->timeout_task) + GNUNET_SCHEDULER_cancel (handle->timeout_task); + if (NULL != handle->identity_handle) + GNUNET_IDENTITY_disconnect (handle->identity_handle); + if (NULL != handle->attr_it) + GNUNET_RECLAIM_get_attributes_stop (handle->attr_it); + if (NULL != handle->ticket_it) + GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it); + if (NULL != handle->idp) + GNUNET_RECLAIM_disconnect (handle->idp); + if (NULL != handle->url) + GNUNET_free (handle->url); + if (NULL != handle->emsg) + GNUNET_free (handle->emsg); + if (NULL != handle->namestore_handle) + GNUNET_NAMESTORE_disconnect (handle->namestore_handle); + if ( NULL != handle->attr_list ) + { + for (claim_entry = handle->attr_list->list_head; + NULL != claim_entry;) + { + claim_tmp = claim_entry; + claim_entry = claim_entry->next; + GNUNET_free(claim_tmp->claim); + GNUNET_free(claim_tmp); + } + GNUNET_free (handle->attr_list); + } + 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); + } + if (NULL != handle->attr_it) + { + GNUNET_free(handle->attr_it); + } + GNUNET_free (handle); +} + +static void +cleanup_handle_delayed (void *cls) +{ + cleanup_handle (cls); +} + + +/** + * Task run on error, sends error message. Cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_error (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + char *json_error; + + GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", + handle->emsg); + if ( 0 == handle->response_code ) + { + handle->response_code = MHD_HTTP_BAD_REQUEST; + } + resp = GNUNET_REST_create_response (json_error); + MHD_add_response_header (resp, "Content-Type", "application/json"); + handle->proc (handle->proc_cls, resp, handle->response_code); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); + GNUNET_free (json_error); +} + + +/** + * Task run on timeout, sends error message. Cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_timeout (void *cls) +{ + struct RequestHandle *handle = cls; + + handle->timeout_task = NULL; + do_error (handle); +} + + +static void +collect_error_cb (void *cls) +{ + struct RequestHandle *handle = cls; + + do_error (handle); +} + +static void +finished_cont (void *cls, + int32_t success, + const char *emsg) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + + resp = GNUNET_REST_create_response (emsg); + if (GNUNET_OK != success) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); +} + + +/** + * Return attributes for identity + * + * @param cls the request handle + */ +static void +return_response (void *cls) +{ + char* result_str; + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + + result_str = json_dumps (handle->resp_object, 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); + GNUNET_free (result_str); + cleanup_handle (handle); +} + +static void +collect_finished_cb (void *cls) +{ + struct RequestHandle *handle = cls; + //Done + handle->attr_it = NULL; + handle->ticket_it = NULL; + GNUNET_SCHEDULER_add_now (&return_response, handle); +} + + +/** + * Collect all attributes for an ego + * + */ +static void +ticket_collect (void *cls, + const struct GNUNET_RECLAIM_Ticket *ticket) +{ + json_t *json_resource; + struct RequestHandle *handle = cls; + json_t *value; + char* tmp; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n"); + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, + sizeof (uint64_t)); + json_resource = json_object (); + GNUNET_free (tmp); + json_array_append (handle->resp_object, + json_resource); + + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + value = json_string (tmp); + json_object_set_new (json_resource, + "issuer", + value); + GNUNET_free (tmp); + json_decref (value); + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + value = json_string (tmp); + json_object_set_new (json_resource, + "audience", + value); + GNUNET_free (tmp); + json_decref (value); + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, + sizeof (uint64_t)); + value = json_string (tmp); + json_object_set_new (json_resource, + "rnd", + value); + GNUNET_free (tmp); + json_decref (value); + GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it); +} + + + +/** + * List tickets for identity request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *identity; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n", + handle->url); + if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= + strlen (handle->url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1; + + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + handle->resp_object = json_array (); + + if (NULL == ego_entry) + { + //Done + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", + identity); + GNUNET_SCHEDULER_add_now (&return_response, handle); + return; + } + priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->ticket_it = GNUNET_RECLAIM_ticket_iteration_start (handle->idp, + priv_key, + &collect_error_cb, + handle, + &ticket_collect, + handle, + &collect_finished_cb, + handle); +} + + +static void +add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; + const char* identity; + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute; + struct GNUNET_TIME_Relative exp; + char term_data[handle->rest_handle->data_size+1]; + json_t *data_json; + json_error_t err; + struct GNUNET_JSON_Specification attrspec[] = { + GNUNET_RECLAIM_JSON_spec_claim (&attribute), + GNUNET_JSON_spec_end() + }; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n", + handle->url); + if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= + strlen (handle->url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1; + + for (ego_entry = handle->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_ERROR, + "Identity unknown (%s)\n", identity); + return; + } + identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + + if (0 >= handle->rest_handle->data_size) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, + JSON_DECODE_ANY, + &err); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (data_json, attrspec, + NULL, NULL)); + json_decref (data_json); + if (NULL == attribute) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse attribute from %s\n", + term_data); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp, + identity_priv, + attribute, + &exp, + &finished_cont, + handle); + GNUNET_JSON_parse_free (attrspec); +} + + + +/** + * Collect all attributes for an ego + * + */ +static void +attr_collect (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) +{ + struct RequestHandle *handle = cls; + json_t *value; + char* tmp_value; + + if ((NULL == attr->name) || (NULL == attr->data)) + { + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", + attr->name); + + tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, + attr->data, + attr->data_size); + + value = json_string (tmp_value); + + json_object_set_new (handle->resp_object, + attr->name, + value); + json_decref (value); + GNUNET_free(tmp_value); + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); +} + + + +/** + * List attributes for identity request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *identity; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n", + handle->url); + if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= + strlen (handle->url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1; + + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + handle->resp_object = json_object (); + + + if (NULL == ego_entry) + { + //Done + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", + identity); + GNUNET_SCHEDULER_add_now (&return_response, handle); + return; + } + priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp, + priv_key, + &collect_error_cb, + handle, + &attr_collect, + handle, + &collect_finished_cb, + handle); +} + + +static void +revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct GNUNET_RECLAIM_Ticket *ticket; + struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk; + char term_data[handle->rest_handle->data_size+1]; + json_t *data_json; + json_error_t err; + struct GNUNET_JSON_Specification tktspec[] = { + GNUNET_RECLAIM_JSON_spec_ticket (&ticket), + GNUNET_JSON_spec_end() + }; + + if (0 >= handle->rest_handle->data_size) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, + JSON_DECODE_ANY, + &err); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (data_json, tktspec, + NULL, NULL)); + json_decref (data_json); + if (NULL == ticket) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse ticket from %s\n", + term_data); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (GNUNET_OK != GNUNET_JSON_parse (data_json, + tktspec, + NULL, NULL)) + { + handle->emsg = GNUNET_strdup ("Not a ticket!\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + GNUNET_JSON_parse_free (tktspec); + json_decref (data_json); + return; + } + + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + { + GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, + &tmp_pk); + if (0 == memcmp (&ticket->identity, + &tmp_pk, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) + break; + } + if (NULL == ego_entry) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Identity unknown\n"); + GNUNET_JSON_parse_free (tktspec); + return; + } + identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp, + identity_priv, + ticket, + &finished_cont, + handle); + GNUNET_JSON_parse_free (tktspec); +} + +static void +consume_cont (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) +{ + struct RequestHandle *handle = cls; + char *val_str; + json_t *value; + + if (NULL == identity) + { + GNUNET_SCHEDULER_add_now (&return_response, handle); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", + attr->name); + val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, + attr->data, + attr->data_size); + if (NULL == val_str) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to parse value for: %s\n", + attr->name); + return; + } + value = json_string(val_str); + json_object_set_new (handle->resp_object, + attr->name, + value); + json_decref (value); + GNUNET_free (val_str); +} + +static void +consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct GNUNET_RECLAIM_Ticket *ticket; + struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk; + char term_data[handle->rest_handle->data_size+1]; + json_t *data_json; + json_error_t err; + struct GNUNET_JSON_Specification tktspec[] = { + GNUNET_RECLAIM_JSON_spec_ticket (&ticket), + GNUNET_JSON_spec_end () + }; + + if (0 >= handle->rest_handle->data_size) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, + JSON_DECODE_ANY, + &err); + if (NULL == data_json) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse JSON Object from %s\n", + term_data); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (GNUNET_OK != GNUNET_JSON_parse (data_json, + tktspec, + NULL, NULL)) + { + handle->emsg = GNUNET_strdup ("Not a ticket!\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + GNUNET_JSON_parse_free(tktspec); + json_decref (data_json); + return; + } + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + { + GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, + &tmp_pk); + if (0 == memcmp (&ticket->audience, + &tmp_pk, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) + break; + } + if (NULL == ego_entry) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Identity unknown\n"); + GNUNET_JSON_parse_free (tktspec); + return; + } + identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->resp_object = json_object (); + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp, + identity_priv, + ticket, + &consume_cont, + handle); + GNUNET_JSON_parse_free (tktspec); +} + + + +/** + * 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); + 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_RECLAIM_ATTRIBUTES, &list_attribute_cont}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &add_attribute_cont}, + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont}, + {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, + &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 +list_ego (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; + ego_entry->identifier = GNUNET_strdup (identifier); + GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); + } + +} + +static void +rest_identity_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->state = ID_REST_STATE_INIT; + handle->rest_handle = rest_handle; + + 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, + &list_ego, + handle); + handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg); + handle->timeout_task = + GNUNET_SCHEDULER_add_delayed (handle->timeout, + &do_timeout, + 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_reclaim_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_RECLAIM; + api->process_request = &rest_identity_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 Provider 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_reclaim_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 Provider REST plugin is finished\n"); + return NULL; +} + +/* end of plugin_rest_reclaim.c */ -- cgit v1.2.3