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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @author Martin Schanzenbach
22 * @author Philippe Buschmann
23 * @file reclaim/plugin_rest_reclaim.c
24 * @brief GNUnet reclaim REST plugin
28 #include "microhttpd.h"
31 #include "gnunet_gns_service.h"
32 #include "gnunet_gnsrecord_lib.h"
33 #include "gnunet_identity_service.h"
34 #include "gnunet_reclaim_attribute_lib.h"
35 #include "gnunet_reclaim_service.h"
36 #include "gnunet_rest_lib.h"
37 #include "gnunet_rest_plugin.h"
38 #include "gnunet_signatures.h"
39 #include "json_reclaim.h"
44 #define GNUNET_REST_API_NS_RECLAIM "/reclaim"
49 #define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/reclaim/attributes"
54 #define GNUNET_REST_API_NS_IDENTITY_TICKETS "/reclaim/tickets"
59 #define GNUNET_REST_API_NS_IDENTITY_REVOKE "/reclaim/revoke"
64 #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/reclaim/consume"
67 * State while collecting all egos
69 #define ID_REST_STATE_INIT 0
72 * Done collecting egos
74 #define ID_REST_STATE_POST_INIT 1
77 * The configuration handle
79 const struct GNUNET_CONFIGURATION_Handle *cfg;
82 * HTTP methods allows for this plugin
84 static char *allow_methods;
87 * @brief struct returned by the initialization function of the plugin
91 const struct GNUNET_CONFIGURATION_Handle *cfg;
102 struct EgoEntry *next;
107 struct EgoEntry *prev;
122 struct GNUNET_IDENTITY_Ego *ego;
131 struct EgoEntry *ego_head;
136 struct EgoEntry *ego_tail;
141 struct EgoEntry *ego_entry;
144 * Pointer to ego private key
146 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
149 * The processing state
154 * Handle to Identity service.
156 struct GNUNET_IDENTITY_Handle *identity_handle;
161 struct GNUNET_REST_RequestHandle *rest_handle;
164 * Attribute claim list
166 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list;
171 struct GNUNET_IDENTITY_Operation *op;
176 struct GNUNET_RECLAIM_Handle *idp;
181 struct GNUNET_RECLAIM_Operation *idp_op;
186 struct GNUNET_RECLAIM_AttributeIterator *attr_it;
191 struct GNUNET_RECLAIM_TicketIterator *ticket_it;
196 struct GNUNET_RECLAIM_Ticket ticket;
199 * Desired timeout for the lookup (default is no timeout).
201 struct GNUNET_TIME_Relative timeout;
204 * ID of a task associated with the resolution process.
206 struct GNUNET_SCHEDULER_Task *timeout_task;
209 * The plugin result processor
211 GNUNET_REST_ResultProcessor proc;
214 * The closure of the result processor
224 * Error response message
240 * Cleanup lookup handle
241 * @param handle Handle to clean up
244 cleanup_handle (struct RequestHandle *handle)
246 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry;
247 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp;
248 struct EgoEntry *ego_entry;
249 struct EgoEntry *ego_tmp;
250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
251 if (NULL != handle->resp_object)
252 json_decref (handle->resp_object);
253 if (NULL != handle->timeout_task)
254 GNUNET_SCHEDULER_cancel (handle->timeout_task);
255 if (NULL != handle->identity_handle)
256 GNUNET_IDENTITY_disconnect (handle->identity_handle);
257 if (NULL != handle->attr_it)
258 GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
259 if (NULL != handle->ticket_it)
260 GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
261 if (NULL != handle->idp)
262 GNUNET_RECLAIM_disconnect (handle->idp);
263 if (NULL != handle->url)
264 GNUNET_free (handle->url);
265 if (NULL != handle->emsg)
266 GNUNET_free (handle->emsg);
267 if (NULL != handle->attr_list)
269 for (claim_entry = handle->attr_list->list_head; NULL != claim_entry;)
271 claim_tmp = claim_entry;
272 claim_entry = claim_entry->next;
273 GNUNET_free (claim_tmp->claim);
274 GNUNET_free (claim_tmp);
276 GNUNET_free (handle->attr_list);
278 for (ego_entry = handle->ego_head; NULL != ego_entry;)
281 ego_entry = ego_entry->next;
282 GNUNET_free (ego_tmp->identifier);
283 GNUNET_free (ego_tmp->keystring);
284 GNUNET_free (ego_tmp);
286 GNUNET_free (handle);
290 cleanup_handle_delayed (void *cls)
292 cleanup_handle (cls);
297 * Task run on error, sends error message. Cleans up everything.
299 * @param cls the `struct RequestHandle`
304 struct RequestHandle *handle = cls;
305 struct MHD_Response *resp;
308 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", handle->emsg);
309 if (0 == handle->response_code)
311 handle->response_code = MHD_HTTP_BAD_REQUEST;
313 resp = GNUNET_REST_create_response (json_error);
314 MHD_add_response_header (resp, "Content-Type", "application/json");
315 handle->proc (handle->proc_cls, resp, handle->response_code);
316 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
317 GNUNET_free (json_error);
322 * Task run on timeout, sends error message. Cleans up everything.
324 * @param cls the `struct RequestHandle`
327 do_timeout (void *cls)
329 struct RequestHandle *handle = cls;
331 handle->timeout_task = NULL;
337 collect_error_cb (void *cls)
339 struct RequestHandle *handle = cls;
345 finished_cont (void *cls, int32_t success, const char *emsg)
347 struct RequestHandle *handle = cls;
348 struct MHD_Response *resp;
350 resp = GNUNET_REST_create_response (emsg);
351 if (GNUNET_OK != success)
353 GNUNET_SCHEDULER_add_now (&do_error, handle);
356 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
357 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
362 * Return attributes for identity
364 * @param cls the request handle
367 return_response (void *cls)
370 struct RequestHandle *handle = cls;
371 struct MHD_Response *resp;
373 result_str = json_dumps (handle->resp_object, 0);
374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
375 resp = GNUNET_REST_create_response (result_str);
376 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
377 GNUNET_free (result_str);
378 cleanup_handle (handle);
382 collect_finished_cb (void *cls)
384 struct RequestHandle *handle = cls;
386 handle->attr_it = NULL;
387 handle->ticket_it = NULL;
388 GNUNET_SCHEDULER_add_now (&return_response, handle);
393 * Collect all attributes for an ego
397 ticket_collect (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
399 json_t *json_resource;
400 struct RequestHandle *handle = cls;
404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
405 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof (uint64_t));
406 json_resource = json_object ();
408 json_array_append (handle->resp_object, json_resource);
411 GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
413 GNUNET_CRYPTO_EcdsaPublicKey));
414 value = json_string (tmp);
415 json_object_set_new (json_resource, "issuer", value);
418 GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
420 GNUNET_CRYPTO_EcdsaPublicKey));
421 value = json_string (tmp);
422 json_object_set_new (json_resource, "audience", value);
424 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof (uint64_t));
425 value = json_string (tmp);
426 json_object_set_new (json_resource, "rnd", value);
428 GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it);
433 * List tickets for identity request
435 * @param con_handle the connection handle
437 * @param cls the RequestHandle
440 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
444 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
445 struct RequestHandle *handle = cls;
446 struct EgoEntry *ego_entry;
449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
450 "Getting tickets for %s.\n",
452 if (strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= strlen (handle->url))
454 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
455 GNUNET_SCHEDULER_add_now (&do_error, handle);
458 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
460 for (ego_entry = handle->ego_head; NULL != ego_entry;
461 ego_entry = ego_entry->next)
462 if (0 == strcmp (identity, ego_entry->identifier))
464 handle->resp_object = json_array ();
466 if (NULL == ego_entry)
469 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
470 GNUNET_SCHEDULER_add_now (&return_response, handle);
473 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
474 handle->idp = GNUNET_RECLAIM_connect (cfg);
476 GNUNET_RECLAIM_ticket_iteration_start (handle->idp,
482 &collect_finished_cb,
488 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
492 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
493 const char *identity;
494 struct RequestHandle *handle = cls;
495 struct EgoEntry *ego_entry;
496 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute;
497 struct GNUNET_TIME_Relative exp;
498 char term_data[handle->rest_handle->data_size + 1];
501 struct GNUNET_JSON_Specification attrspec[] =
502 {GNUNET_RECLAIM_JSON_spec_claim (&attribute), GNUNET_JSON_spec_end ()};
504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
505 "Adding an attribute for %s.\n",
507 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
509 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
510 GNUNET_SCHEDULER_add_now (&do_error, handle);
513 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
515 for (ego_entry = handle->ego_head; NULL != ego_entry;
516 ego_entry = ego_entry->next)
517 if (0 == strcmp (identity, ego_entry->identifier))
520 if (NULL == ego_entry)
522 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
525 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
527 if (0 >= handle->rest_handle->data_size)
529 GNUNET_SCHEDULER_add_now (&do_error, handle);
533 term_data[handle->rest_handle->data_size] = '\0';
534 GNUNET_memcpy (term_data,
535 handle->rest_handle->data,
536 handle->rest_handle->data_size);
537 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
538 GNUNET_assert (GNUNET_OK ==
539 GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
540 json_decref (data_json);
541 if (NULL == attribute)
543 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
544 "Unable to parse attribute from %s\n",
546 GNUNET_SCHEDULER_add_now (&do_error, handle);
550 * New ID for attribute
552 if (0 == attribute->id)
554 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
555 handle->idp = GNUNET_RECLAIM_connect (cfg);
556 exp = GNUNET_TIME_UNIT_HOURS;
557 handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
563 GNUNET_JSON_parse_free (attrspec);
568 * Collect all attributes for an ego
572 attr_collect (void *cls,
573 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
574 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
576 struct RequestHandle *handle = cls;
582 if ((NULL == attr->name) || (NULL == attr->data))
584 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
590 tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
594 attr_obj = json_object ();
595 json_object_set_new (attr_obj, "value", json_string (tmp_value));
596 json_object_set_new (attr_obj, "name", json_string (attr->name));
597 type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
598 json_object_set_new (attr_obj, "type", json_string (type));
599 id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof (uint64_t));
600 json_object_set_new (attr_obj, "id", json_string (id_str));
601 json_array_append (handle->resp_object, attr_obj);
602 json_decref (attr_obj);
603 GNUNET_free (tmp_value);
604 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
609 * List attributes for identity request
611 * @param con_handle the connection handle
613 * @param cls the RequestHandle
616 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
620 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
621 struct RequestHandle *handle = cls;
622 struct EgoEntry *ego_entry;
625 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
626 "Getting attributes for %s.\n",
628 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
630 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
631 GNUNET_SCHEDULER_add_now (&do_error, handle);
634 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
636 for (ego_entry = handle->ego_head; NULL != ego_entry;
637 ego_entry = ego_entry->next)
638 if (0 == strcmp (identity, ego_entry->identifier))
640 handle->resp_object = json_array ();
643 if (NULL == ego_entry)
646 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
647 GNUNET_SCHEDULER_add_now (&return_response, handle);
650 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
651 handle->idp = GNUNET_RECLAIM_connect (cfg);
652 handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
658 &collect_finished_cb,
664 delete_finished_cb (void *cls, int32_t success, const char *emsg)
666 struct RequestHandle *handle = cls;
667 struct MHD_Response *resp;
669 resp = GNUNET_REST_create_response (emsg);
670 if (GNUNET_OK != success)
672 GNUNET_SCHEDULER_add_now (&do_error, handle);
675 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
676 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
681 * List attributes for identity request
683 * @param con_handle the connection handle
685 * @param cls the RequestHandle
688 delete_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
692 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
693 struct RequestHandle *handle = cls;
694 struct GNUNET_RECLAIM_ATTRIBUTE_Claim attr;
695 struct EgoEntry *ego_entry;
696 char *identity_id_str;
700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attributes.\n");
701 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
703 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
704 GNUNET_SCHEDULER_add_now (&do_error, handle);
708 strdup (handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1);
709 identity = strtok (identity_id_str, "/");
710 id = strtok (NULL, "/");
711 if ((NULL == identity) || (NULL == id))
713 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
714 GNUNET_free (identity_id_str);
715 GNUNET_SCHEDULER_add_now (&do_error, handle);
719 for (ego_entry = handle->ego_head; NULL != ego_entry;
720 ego_entry = ego_entry->next)
721 if (0 == strcmp (identity, ego_entry->identifier))
723 handle->resp_object = json_array ();
724 if (NULL == ego_entry)
727 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
728 GNUNET_free (identity_id_str);
729 GNUNET_SCHEDULER_add_now (&return_response, handle);
732 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
733 handle->idp = GNUNET_RECLAIM_connect (cfg);
734 memset (&attr, 0, sizeof (struct GNUNET_RECLAIM_ATTRIBUTE_Claim));
735 GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof (uint64_t));
737 handle->idp_op = GNUNET_RECLAIM_attribute_delete (handle->idp,
742 GNUNET_free (identity_id_str);
747 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
751 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
752 struct RequestHandle *handle = cls;
753 struct EgoEntry *ego_entry;
754 struct GNUNET_RECLAIM_Ticket *ticket = NULL;
755 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
756 char term_data[handle->rest_handle->data_size + 1];
759 struct GNUNET_JSON_Specification tktspec[] =
760 {GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end ()};
762 if (0 >= handle->rest_handle->data_size)
764 GNUNET_SCHEDULER_add_now (&do_error, handle);
768 term_data[handle->rest_handle->data_size] = '\0';
769 GNUNET_memcpy (term_data,
770 handle->rest_handle->data,
771 handle->rest_handle->data_size);
772 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
773 if ((NULL == data_json) ||
774 (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)))
776 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
777 GNUNET_SCHEDULER_add_now (&do_error, handle);
778 GNUNET_JSON_parse_free (tktspec);
779 if (NULL != data_json)
780 json_decref (data_json);
783 json_decref (data_json);
786 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
787 "Unable to parse ticket from %s\n",
789 GNUNET_SCHEDULER_add_now (&do_error, handle);
793 for (ego_entry = handle->ego_head; NULL != ego_entry;
794 ego_entry = ego_entry->next)
796 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
797 if (0 == memcmp (&ticket->identity,
799 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
802 if (NULL == ego_entry)
804 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
805 GNUNET_JSON_parse_free (tktspec);
808 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
810 handle->idp = GNUNET_RECLAIM_connect (cfg);
811 handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
816 GNUNET_JSON_parse_free (tktspec);
820 consume_cont (void *cls,
821 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
822 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
824 struct RequestHandle *handle = cls;
828 if (NULL == identity)
830 GNUNET_SCHEDULER_add_now (&return_response, handle);
834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
835 val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
840 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
841 "Failed to parse value for: %s\n",
845 value = json_string (val_str);
846 json_object_set_new (handle->resp_object, attr->name, value);
848 GNUNET_free (val_str);
852 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
856 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
857 struct RequestHandle *handle = cls;
858 struct EgoEntry *ego_entry;
859 struct GNUNET_RECLAIM_Ticket *ticket;
860 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
861 char term_data[handle->rest_handle->data_size + 1];
864 struct GNUNET_JSON_Specification tktspec[] =
865 {GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end ()};
867 if (0 >= handle->rest_handle->data_size)
869 GNUNET_SCHEDULER_add_now (&do_error, handle);
873 term_data[handle->rest_handle->data_size] = '\0';
874 GNUNET_memcpy (term_data,
875 handle->rest_handle->data,
876 handle->rest_handle->data_size);
877 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
878 if (NULL == data_json)
880 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
881 "Unable to parse JSON Object from %s\n",
883 GNUNET_SCHEDULER_add_now (&do_error, handle);
886 if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL))
888 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
889 GNUNET_SCHEDULER_add_now (&do_error, handle);
890 GNUNET_JSON_parse_free (tktspec);
891 json_decref (data_json);
894 for (ego_entry = handle->ego_head; NULL != ego_entry;
895 ego_entry = ego_entry->next)
897 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
898 if (0 == memcmp (&ticket->audience,
900 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
903 if (NULL == ego_entry)
905 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
906 GNUNET_JSON_parse_free (tktspec);
909 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
910 handle->resp_object = json_object ();
911 handle->idp = GNUNET_RECLAIM_connect (cfg);
912 handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
917 GNUNET_JSON_parse_free (tktspec);
922 * Respond to OPTIONS request
924 * @param con_handle the connection handle
926 * @param cls the RequestHandle
929 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
933 struct MHD_Response *resp;
934 struct RequestHandle *handle = cls;
936 // For now, independent of path return all options
937 resp = GNUNET_REST_create_response (NULL);
938 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
939 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
940 cleanup_handle (handle);
945 * Handle rest request
947 * @param handle the request handle
950 init_cont (struct RequestHandle *handle)
952 struct GNUNET_REST_RequestHandlerError err;
953 static const struct GNUNET_REST_RequestHandler handlers[] =
954 {{MHD_HTTP_METHOD_GET,
955 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
956 &list_attribute_cont},
957 {MHD_HTTP_METHOD_POST,
958 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
959 &add_attribute_cont},
960 {MHD_HTTP_METHOD_DELETE,
961 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
962 &delete_attribute_cont},
963 {MHD_HTTP_METHOD_GET,
964 GNUNET_REST_API_NS_IDENTITY_TICKETS,
966 {MHD_HTTP_METHOD_POST,
967 GNUNET_REST_API_NS_IDENTITY_REVOKE,
968 &revoke_ticket_cont},
969 {MHD_HTTP_METHOD_POST,
970 GNUNET_REST_API_NS_IDENTITY_CONSUME,
971 &consume_ticket_cont},
972 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, &options_cont},
973 GNUNET_REST_HANDLER_END};
976 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
978 handle->response_code = err.error_code;
979 GNUNET_SCHEDULER_add_now (&do_error, handle);
984 * If listing is enabled, prints information about the egos.
986 * This function is initially called for all egos and then again
987 * whenever a ego's identifier changes or if it is deleted. At the
988 * end of the initial pass over all egos, the function is once called
989 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
990 * be invoked in the future or that there was an error.
992 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
993 * this function is only called ONCE, and 'NULL' being passed in
994 * 'ego' does indicate an error (i.e. name is taken or no default
995 * value is known). If 'ego' is non-NULL and if '*ctx'
996 * is set in those callbacks, the value WILL be passed to a subsequent
997 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
998 * that one was not NULL).
1000 * When an identity is renamed, this function is called with the
1001 * (known) ego but the NEW identifier.
1003 * When an identity is deleted, this function is called with the
1004 * (known) ego and "NULL" for the 'identifier'. In this case,
1005 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1008 * @param cls closure
1009 * @param ego ego handle
1010 * @param ctx context for application to store data for this ego
1011 * (during the lifetime of this process, initially NULL)
1012 * @param identifier identifier assigned by the user for this ego,
1013 * NULL if the user just deleted the ego and it
1014 * must thus no longer be used
1017 list_ego (void *cls,
1018 struct GNUNET_IDENTITY_Ego *ego,
1020 const char *identifier)
1022 struct RequestHandle *handle = cls;
1023 struct EgoEntry *ego_entry;
1024 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1026 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1028 handle->state = ID_REST_STATE_POST_INIT;
1032 if (ID_REST_STATE_INIT == handle->state)
1034 ego_entry = GNUNET_new (struct EgoEntry);
1035 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1036 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1037 ego_entry->ego = ego;
1038 ego_entry->identifier = GNUNET_strdup (identifier);
1039 GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
1046 rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1047 GNUNET_REST_ResultProcessor proc,
1050 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1051 handle->response_code = 0;
1052 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1053 handle->proc_cls = proc_cls;
1054 handle->proc = proc;
1055 handle->state = ID_REST_STATE_INIT;
1056 handle->rest_handle = rest_handle;
1058 handle->url = GNUNET_strdup (rest_handle->url);
1059 if (handle->url[strlen (handle->url) - 1] == '/')
1060 handle->url[strlen (handle->url) - 1] = '\0';
1061 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1062 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
1063 handle->timeout_task =
1064 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
1065 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1069 * Entry point for the plugin.
1071 * @param cls Config info
1072 * @return NULL on error, otherwise the plugin context
1075 libgnunet_plugin_rest_reclaim_init (void *cls)
1077 static struct Plugin plugin;
1078 struct GNUNET_REST_Plugin *api;
1081 if (NULL != plugin.cfg)
1082 return NULL; /* can only initialize once! */
1083 memset (&plugin, 0, sizeof (struct Plugin));
1085 api = GNUNET_new (struct GNUNET_REST_Plugin);
1087 api->name = GNUNET_REST_API_NS_RECLAIM;
1088 api->process_request = &rest_identity_process_request;
1089 GNUNET_asprintf (&allow_methods,
1090 "%s, %s, %s, %s, %s",
1091 MHD_HTTP_METHOD_GET,
1092 MHD_HTTP_METHOD_POST,
1093 MHD_HTTP_METHOD_PUT,
1094 MHD_HTTP_METHOD_DELETE,
1095 MHD_HTTP_METHOD_OPTIONS);
1097 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1098 _ ("Identity Provider REST API initialized\n"));
1104 * Exit point from the plugin.
1106 * @param cls the plugin context (as returned by "init")
1107 * @return always NULL
1110 libgnunet_plugin_rest_reclaim_done (void *cls)
1112 struct GNUNET_REST_Plugin *api = cls;
1113 struct Plugin *plugin = api->cls;
1116 GNUNET_free_non_null (allow_methods);
1118 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1119 "Identity Provider REST plugin is finished\n");
1123 /* end of plugin_rest_reclaim.c */