2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * @author Martin Schanzenbach
20 * @author Philippe Buschmann
21 * @file reclaim/plugin_rest_reclaim.c
22 * @brief GNUnet reclaim REST plugin
27 #include "gnunet_rest_plugin.h"
28 #include "gnunet_identity_service.h"
29 #include "gnunet_gns_service.h"
30 #include "gnunet_gnsrecord_lib.h"
31 #include "gnunet_namestore_service.h"
32 #include "gnunet_rest_lib.h"
33 #include "gnunet_jsonapi_lib.h"
34 #include "gnunet_jsonapi_util.h"
35 #include "microhttpd.h"
38 #include "gnunet_signatures.h"
39 #include "gnunet_reclaim_attribute_lib.h"
40 #include "gnunet_reclaim_service.h"
45 #define GNUNET_REST_API_NS_RECLAIM "/reclaim"
50 #define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/reclaim/attributes"
55 #define GNUNET_REST_API_NS_IDENTITY_TICKETS "/reclaim/tickets"
60 #define GNUNET_REST_API_NS_IDENTITY_REVOKE "/reclaim/revoke"
65 #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/reclaim/consume"
70 #define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE "attribute"
75 #define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket"
81 #define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE_VALUE "value"
84 * State while collecting all egos
86 #define ID_REST_STATE_INIT 0
89 * Done collecting egos
91 #define ID_REST_STATE_POST_INIT 1
94 * The configuration handle
96 const struct GNUNET_CONFIGURATION_Handle *cfg;
99 * HTTP methods allows for this plugin
101 static char* allow_methods;
104 * @brief struct returned by the initialization function of the plugin
108 const struct GNUNET_CONFIGURATION_Handle *cfg;
119 struct EgoEntry *next;
124 struct EgoEntry *prev;
139 struct GNUNET_IDENTITY_Ego *ego;
148 struct EgoEntry *ego_head;
153 struct EgoEntry *ego_tail;
158 struct EgoEntry *ego_entry;
161 * Pointer to ego private key
163 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
166 * The processing state
171 * Handle to Identity service.
173 struct GNUNET_IDENTITY_Handle *identity_handle;
178 struct GNUNET_REST_RequestHandle *rest_handle;
181 * Handle to NAMESTORE
183 struct GNUNET_NAMESTORE_Handle *namestore_handle;
186 * Iterator for NAMESTORE
188 struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
191 * Attribute claim list
193 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list;
198 struct GNUNET_IDENTITY_Operation *op;
203 struct GNUNET_RECLAIM_Handle *idp;
208 struct GNUNET_RECLAIM_Operation *idp_op;
213 struct GNUNET_RECLAIM_AttributeIterator *attr_it;
218 struct GNUNET_RECLAIM_TicketIterator *ticket_it;
223 struct GNUNET_RECLAIM_Ticket ticket;
226 * Desired timeout for the lookup (default is no timeout).
228 struct GNUNET_TIME_Relative timeout;
231 * ID of a task associated with the resolution process.
233 struct GNUNET_SCHEDULER_Task *timeout_task;
236 * The plugin result processor
238 GNUNET_REST_ResultProcessor proc;
241 * The closure of the result processor
251 * Error response message
263 struct GNUNET_JSONAPI_Document *resp_object;
268 * Cleanup lookup handle
269 * @param handle Handle to clean up
272 cleanup_handle (struct RequestHandle *handle)
274 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry;
275 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp;
276 struct EgoEntry *ego_entry;
277 struct EgoEntry *ego_tmp;
278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
280 if (NULL != handle->resp_object)
281 GNUNET_JSONAPI_document_delete (handle->resp_object);
282 if (NULL != handle->timeout_task)
283 GNUNET_SCHEDULER_cancel (handle->timeout_task);
284 if (NULL != handle->identity_handle)
285 GNUNET_IDENTITY_disconnect (handle->identity_handle);
286 if (NULL != handle->attr_it)
287 GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
288 if (NULL != handle->ticket_it)
289 GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
290 if (NULL != handle->idp)
291 GNUNET_RECLAIM_disconnect (handle->idp);
292 if (NULL != handle->url)
293 GNUNET_free (handle->url);
294 if (NULL != handle->emsg)
295 GNUNET_free (handle->emsg);
296 if (NULL != handle->namestore_handle)
297 GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
298 if ( NULL != handle->attr_list )
300 for (claim_entry = handle->attr_list->list_head;
301 NULL != claim_entry;)
303 claim_tmp = claim_entry;
304 claim_entry = claim_entry->next;
305 GNUNET_free(claim_tmp->claim);
306 GNUNET_free(claim_tmp);
308 GNUNET_free (handle->attr_list);
310 for (ego_entry = handle->ego_head;
314 ego_entry = ego_entry->next;
315 GNUNET_free (ego_tmp->identifier);
316 GNUNET_free (ego_tmp->keystring);
317 GNUNET_free (ego_tmp);
319 if (NULL != handle->attr_it)
321 GNUNET_free(handle->attr_it);
323 GNUNET_free (handle);
327 cleanup_handle_delayed (void *cls)
329 cleanup_handle (cls);
334 * Task run on error, sends error message. Cleans up everything.
336 * @param cls the `struct RequestHandle`
341 struct RequestHandle *handle = cls;
342 struct MHD_Response *resp;
345 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }",
347 if ( 0 == handle->response_code )
349 handle->response_code = MHD_HTTP_BAD_REQUEST;
351 resp = GNUNET_REST_create_response (json_error);
352 MHD_add_response_header (resp, "Content-Type", "application/json");
353 handle->proc (handle->proc_cls, resp, handle->response_code);
354 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
355 GNUNET_free (json_error);
360 * Task run on timeout, sends error message. Cleans up everything.
362 * @param cls the `struct RequestHandle`
365 do_timeout (void *cls)
367 struct RequestHandle *handle = cls;
369 handle->timeout_task = NULL;
375 collect_error_cb (void *cls)
377 struct RequestHandle *handle = cls;
383 finished_cont (void *cls,
387 struct RequestHandle *handle = cls;
388 struct MHD_Response *resp;
390 resp = GNUNET_REST_create_response (emsg);
391 if (GNUNET_OK != success)
393 GNUNET_SCHEDULER_add_now (&do_error, handle);
396 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
397 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
402 * Return attributes for identity
404 * @param cls the request handle
407 return_response (void *cls)
410 struct RequestHandle *handle = cls;
411 struct MHD_Response *resp;
413 GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str);
414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
415 resp = GNUNET_REST_create_response (result_str);
416 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
417 GNUNET_free (result_str);
418 cleanup_handle (handle);
422 collect_finished_cb (void *cls)
424 struct RequestHandle *handle = cls;
426 handle->attr_it = NULL;
427 handle->ticket_it = NULL;
428 GNUNET_SCHEDULER_add_now (&return_response, handle);
433 * Collect all attributes for an ego
437 ticket_collect (void *cls,
438 const struct GNUNET_RECLAIM_Ticket *ticket)
440 struct GNUNET_JSONAPI_Resource *json_resource;
441 struct RequestHandle *handle = cls;
445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
446 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
448 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET,
451 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
453 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
454 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
455 value = json_string (tmp);
456 GNUNET_JSONAPI_resource_add_attr (json_resource,
461 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
462 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
463 value = json_string (tmp);
464 GNUNET_JSONAPI_resource_add_attr (json_resource,
469 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
471 value = json_string (tmp);
472 GNUNET_JSONAPI_resource_add_attr (json_resource,
477 GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it);
483 * List tickets for identity request
485 * @param con_handle the connection handle
487 * @param cls the RequestHandle
490 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
494 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
495 struct RequestHandle *handle = cls;
496 struct EgoEntry *ego_entry;
499 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
501 if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
502 strlen (handle->url))
504 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
505 GNUNET_SCHEDULER_add_now (&do_error, handle);
508 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
510 for (ego_entry = handle->ego_head;
512 ego_entry = ego_entry->next)
513 if (0 == strcmp (identity, ego_entry->identifier))
515 handle->resp_object = GNUNET_JSONAPI_document_new ();
517 if (NULL == ego_entry)
520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
522 GNUNET_SCHEDULER_add_now (&return_response, handle);
525 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
526 handle->idp = GNUNET_RECLAIM_connect (cfg);
527 handle->ticket_it = GNUNET_RECLAIM_ticket_iteration_start (handle->idp,
533 &collect_finished_cb,
539 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
543 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
544 const char* identity;
545 const char* name_str;
546 const char* value_str;
549 struct RequestHandle *handle = cls;
550 struct EgoEntry *ego_entry;
551 struct MHD_Response *resp;
552 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute;
553 struct GNUNET_JSONAPI_Document *json_obj;
554 struct GNUNET_JSONAPI_Resource *json_res;
555 struct GNUNET_TIME_Relative exp;
556 char term_data[handle->rest_handle->data_size+1];
561 struct GNUNET_JSON_Specification docspec[] = {
562 GNUNET_JSON_spec_jsonapi_document (&json_obj),
563 GNUNET_JSON_spec_end()
566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
568 if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >=
569 strlen (handle->url))
571 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
572 GNUNET_SCHEDULER_add_now (&do_error, handle);
575 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
577 for (ego_entry = handle->ego_head;
579 ego_entry = ego_entry->next)
580 if (0 == strcmp (identity, ego_entry->identifier))
583 if (NULL == ego_entry)
585 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
586 "Identity unknown (%s)\n", identity);
587 GNUNET_JSONAPI_document_delete (json_obj);
590 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
592 if (0 >= handle->rest_handle->data_size)
594 GNUNET_SCHEDULER_add_now (&do_error, handle);
598 term_data[handle->rest_handle->data_size] = '\0';
599 GNUNET_memcpy (term_data,
600 handle->rest_handle->data,
601 handle->rest_handle->data_size);
602 data_json = json_loads (term_data,
605 GNUNET_assert (GNUNET_OK ==
606 GNUNET_JSON_parse (data_json, docspec,
608 json_decref (data_json);
609 if (NULL == json_obj)
611 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
612 "Unable to parse JSONAPI Object from %s\n",
614 GNUNET_SCHEDULER_add_now (&do_error, handle);
617 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
619 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
620 "Cannot create more than 1 resource! (Got %d)\n",
621 GNUNET_JSONAPI_document_resource_count (json_obj));
622 GNUNET_JSONAPI_document_delete (json_obj);
623 GNUNET_SCHEDULER_add_now (&do_error, handle);
626 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
627 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
628 GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE))
630 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
631 "Unsupported JSON data type\n");
632 GNUNET_JSONAPI_document_delete (json_obj);
633 resp = GNUNET_REST_create_response (NULL);
634 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
635 cleanup_handle (handle);
638 name_str = GNUNET_JSONAPI_resource_get_id (json_res);
639 exp_json = GNUNET_JSONAPI_resource_read_attr (json_res,
641 exp_str = json_string_value (exp_json);
642 if (NULL == exp_str) {
643 exp = GNUNET_TIME_UNIT_HOURS;
645 if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (exp_str,
647 exp = GNUNET_TIME_UNIT_HOURS;
651 value_json = GNUNET_JSONAPI_resource_read_attr (json_res,
653 value_str = json_string_value (value_json);
654 attribute = GNUNET_RECLAIM_ATTRIBUTE_claim_new (name_str,
655 GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING,
657 strlen (value_str) + 1);
658 handle->idp = GNUNET_RECLAIM_connect (cfg);
659 handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
665 GNUNET_free (attribute);
666 GNUNET_JSONAPI_document_delete (json_obj);
672 * Collect all attributes for an ego
676 attr_collect (void *cls,
677 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
678 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
680 struct GNUNET_JSONAPI_Resource *json_resource;
681 struct RequestHandle *handle = cls;
685 if ((NULL == attr->name) || (NULL == attr->data))
687 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
693 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE,
695 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
697 tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
701 value = json_string (tmp_value);
703 GNUNET_JSONAPI_resource_add_attr (json_resource,
707 GNUNET_free(tmp_value);
708 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
714 * List attributes for identity request
716 * @param con_handle the connection handle
718 * @param cls the RequestHandle
721 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
725 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
726 struct RequestHandle *handle = cls;
727 struct EgoEntry *ego_entry;
730 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
732 if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >=
733 strlen (handle->url))
735 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
736 GNUNET_SCHEDULER_add_now (&do_error, handle);
739 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
741 for (ego_entry = handle->ego_head;
743 ego_entry = ego_entry->next)
744 if (0 == strcmp (identity, ego_entry->identifier))
746 handle->resp_object = GNUNET_JSONAPI_document_new ();
749 if (NULL == ego_entry)
752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
754 GNUNET_SCHEDULER_add_now (&return_response, handle);
757 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
758 handle->idp = GNUNET_RECLAIM_connect (cfg);
759 handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
765 &collect_finished_cb,
771 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
775 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
776 const char* identity_str;
777 const char* audience_str;
780 struct RequestHandle *handle = cls;
781 struct EgoEntry *ego_entry;
782 struct MHD_Response *resp;
783 struct GNUNET_RECLAIM_Ticket ticket;
784 struct GNUNET_JSONAPI_Document *json_obj;
785 struct GNUNET_JSONAPI_Resource *json_res;
786 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
787 char term_data[handle->rest_handle->data_size+1];
789 json_t *identity_json;
790 json_t *audience_json;
793 struct GNUNET_JSON_Specification docspec[] = {
794 GNUNET_JSON_spec_jsonapi_document (&json_obj),
795 GNUNET_JSON_spec_end()
798 if (0 >= handle->rest_handle->data_size)
800 GNUNET_SCHEDULER_add_now (&do_error, handle);
804 term_data[handle->rest_handle->data_size] = '\0';
805 GNUNET_memcpy (term_data,
806 handle->rest_handle->data,
807 handle->rest_handle->data_size);
808 data_json = json_loads (term_data,
811 GNUNET_assert (GNUNET_OK ==
812 GNUNET_JSON_parse (data_json, docspec,
814 json_decref (data_json);
815 if (NULL == json_obj)
817 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
818 "Unable to parse JSONAPI Object from %s\n",
820 GNUNET_SCHEDULER_add_now (&do_error, handle);
823 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
825 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
826 "Cannot create more than 1 resource! (Got %d)\n",
827 GNUNET_JSONAPI_document_resource_count (json_obj));
828 GNUNET_JSONAPI_document_delete (json_obj);
829 GNUNET_SCHEDULER_add_now (&do_error, handle);
832 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
833 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
834 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
836 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
837 "Unsupported JSON data type\n");
838 GNUNET_JSONAPI_document_delete (json_obj);
839 resp = GNUNET_REST_create_response (NULL);
840 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
841 cleanup_handle (handle);
844 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
846 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
848 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
850 rnd_str = json_string_value (rnd_json);
851 identity_str = json_string_value (identity_json);
852 audience_str = json_string_value (audience_json);
854 GNUNET_STRINGS_string_to_data (rnd_str,
858 GNUNET_STRINGS_string_to_data (identity_str,
859 strlen (identity_str),
861 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
862 GNUNET_STRINGS_string_to_data (audience_str,
863 strlen (audience_str),
865 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
867 for (ego_entry = handle->ego_head;
869 ego_entry = ego_entry->next)
871 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
873 if (0 == memcmp (&ticket.identity,
875 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
878 if (NULL == ego_entry)
880 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
881 "Identity unknown (%s)\n", identity_str);
882 GNUNET_JSONAPI_document_delete (json_obj);
885 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
887 handle->idp = GNUNET_RECLAIM_connect (cfg);
888 handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
893 GNUNET_JSONAPI_document_delete (json_obj);
897 consume_cont (void *cls,
898 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
899 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
901 struct RequestHandle *handle = cls;
902 struct GNUNET_JSONAPI_Resource *json_resource;
905 if (NULL == identity)
907 GNUNET_SCHEDULER_add_now (&return_response, handle);
911 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
913 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE,
915 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
917 value = json_string (attr->data);
918 GNUNET_JSONAPI_resource_add_attr (json_resource,
925 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
929 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
930 const char* identity_str;
931 const char* audience_str;
934 struct RequestHandle *handle = cls;
935 struct EgoEntry *ego_entry;
936 struct MHD_Response *resp;
937 struct GNUNET_RECLAIM_Ticket ticket;
938 struct GNUNET_JSONAPI_Document *json_obj;
939 struct GNUNET_JSONAPI_Resource *json_res;
940 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
941 char term_data[handle->rest_handle->data_size+1];
943 json_t *identity_json;
944 json_t *audience_json;
947 struct GNUNET_JSON_Specification docspec[] = {
948 GNUNET_JSON_spec_jsonapi_document (&json_obj),
949 GNUNET_JSON_spec_end()
952 if (0 >= handle->rest_handle->data_size)
954 GNUNET_SCHEDULER_add_now (&do_error, handle);
958 term_data[handle->rest_handle->data_size] = '\0';
959 GNUNET_memcpy (term_data,
960 handle->rest_handle->data,
961 handle->rest_handle->data_size);
962 data_json = json_loads (term_data,
965 GNUNET_assert (GNUNET_OK ==
966 GNUNET_JSON_parse (data_json, docspec,
968 json_decref (data_json);
969 if (NULL == json_obj)
971 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
972 "Unable to parse JSONAPI Object from %s\n",
974 GNUNET_SCHEDULER_add_now (&do_error, handle);
977 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
979 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
980 "Cannot create more than 1 resource! (Got %d)\n",
981 GNUNET_JSONAPI_document_resource_count (json_obj));
982 GNUNET_JSONAPI_document_delete (json_obj);
983 GNUNET_SCHEDULER_add_now (&do_error, handle);
986 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
987 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
988 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
990 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
991 "Unsupported JSON data type\n");
992 GNUNET_JSONAPI_document_delete (json_obj);
993 resp = GNUNET_REST_create_response (NULL);
994 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
995 cleanup_handle (handle);
998 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1000 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1002 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1004 rnd_str = json_string_value (rnd_json);
1005 identity_str = json_string_value (identity_json);
1006 audience_str = json_string_value (audience_json);
1008 GNUNET_STRINGS_string_to_data (rnd_str,
1012 GNUNET_STRINGS_string_to_data (identity_str,
1013 strlen (identity_str),
1015 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1016 GNUNET_STRINGS_string_to_data (audience_str,
1017 strlen (audience_str),
1019 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1021 for (ego_entry = handle->ego_head;
1023 ego_entry = ego_entry->next)
1025 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
1027 if (0 == memcmp (&ticket.audience,
1029 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1032 if (NULL == ego_entry)
1034 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1035 "Identity unknown (%s)\n", identity_str);
1036 GNUNET_JSONAPI_document_delete (json_obj);
1039 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1040 handle->resp_object = GNUNET_JSONAPI_document_new ();
1041 handle->idp = GNUNET_RECLAIM_connect (cfg);
1042 handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
1047 GNUNET_JSONAPI_document_delete (json_obj);
1053 * Respond to OPTIONS request
1055 * @param con_handle the connection handle
1056 * @param url the url
1057 * @param cls the RequestHandle
1060 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1064 struct MHD_Response *resp;
1065 struct RequestHandle *handle = cls;
1067 //For now, independent of path return all options
1068 resp = GNUNET_REST_create_response (NULL);
1069 MHD_add_response_header (resp,
1070 "Access-Control-Allow-Methods",
1072 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1073 cleanup_handle (handle);
1078 * Handle rest request
1080 * @param handle the request handle
1083 init_cont (struct RequestHandle *handle)
1085 struct GNUNET_REST_RequestHandlerError err;
1086 static const struct GNUNET_REST_RequestHandler handlers[] = {
1087 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &list_attribute_cont},
1088 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &add_attribute_cont},
1089 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
1090 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
1091 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
1092 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM,
1094 GNUNET_REST_HANDLER_END
1097 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1102 handle->response_code = err.error_code;
1103 GNUNET_SCHEDULER_add_now (&do_error, handle);
1108 * If listing is enabled, prints information about the egos.
1110 * This function is initially called for all egos and then again
1111 * whenever a ego's identifier changes or if it is deleted. At the
1112 * end of the initial pass over all egos, the function is once called
1113 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1114 * be invoked in the future or that there was an error.
1116 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1117 * this function is only called ONCE, and 'NULL' being passed in
1118 * 'ego' does indicate an error (i.e. name is taken or no default
1119 * value is known). If 'ego' is non-NULL and if '*ctx'
1120 * is set in those callbacks, the value WILL be passed to a subsequent
1121 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1122 * that one was not NULL).
1124 * When an identity is renamed, this function is called with the
1125 * (known) ego but the NEW identifier.
1127 * When an identity is deleted, this function is called with the
1128 * (known) ego and "NULL" for the 'identifier'. In this case,
1129 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1132 * @param cls closure
1133 * @param ego ego handle
1134 * @param ctx context for application to store data for this ego
1135 * (during the lifetime of this process, initially NULL)
1136 * @param identifier identifier assigned by the user for this ego,
1137 * NULL if the user just deleted the ego and it
1138 * must thus no longer be used
1141 list_ego (void *cls,
1142 struct GNUNET_IDENTITY_Ego *ego,
1144 const char *identifier)
1146 struct RequestHandle *handle = cls;
1147 struct EgoEntry *ego_entry;
1148 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1150 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1152 handle->state = ID_REST_STATE_POST_INIT;
1156 if (ID_REST_STATE_INIT == handle->state) {
1157 ego_entry = GNUNET_new (struct EgoEntry);
1158 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1159 ego_entry->keystring =
1160 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1161 ego_entry->ego = ego;
1162 ego_entry->identifier = GNUNET_strdup (identifier);
1163 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1169 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1170 GNUNET_REST_ResultProcessor proc,
1173 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1174 handle->response_code = 0;
1175 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1176 handle->proc_cls = proc_cls;
1177 handle->proc = proc;
1178 handle->state = ID_REST_STATE_INIT;
1179 handle->rest_handle = rest_handle;
1181 handle->url = GNUNET_strdup (rest_handle->url);
1182 if (handle->url[strlen (handle->url)-1] == '/')
1183 handle->url[strlen (handle->url)-1] = '\0';
1184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1186 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1189 handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
1190 handle->timeout_task =
1191 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1199 * Entry point for the plugin.
1201 * @param cls Config info
1202 * @return NULL on error, otherwise the plugin context
1205 libgnunet_plugin_rest_reclaim_init (void *cls)
1207 static struct Plugin plugin;
1208 struct GNUNET_REST_Plugin *api;
1211 if (NULL != plugin.cfg)
1212 return NULL; /* can only initialize once! */
1213 memset (&plugin, 0, sizeof (struct Plugin));
1215 api = GNUNET_new (struct GNUNET_REST_Plugin);
1217 api->name = GNUNET_REST_API_NS_RECLAIM;
1218 api->process_request = &rest_identity_process_request;
1219 GNUNET_asprintf (&allow_methods,
1220 "%s, %s, %s, %s, %s",
1221 MHD_HTTP_METHOD_GET,
1222 MHD_HTTP_METHOD_POST,
1223 MHD_HTTP_METHOD_PUT,
1224 MHD_HTTP_METHOD_DELETE,
1225 MHD_HTTP_METHOD_OPTIONS);
1227 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1228 _("Identity Provider REST API initialized\n"));
1234 * Exit point from the plugin.
1236 * @param cls the plugin context (as returned by "init")
1237 * @return always NULL
1240 libgnunet_plugin_rest_reclaim_done (void *cls)
1242 struct GNUNET_REST_Plugin *api = cls;
1243 struct Plugin *plugin = api->cls;
1246 GNUNET_free_non_null (allow_methods);
1248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1249 "Identity Provider REST plugin is finished\n");
1253 /* end of plugin_rest_reclaim.c */