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;
251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
252 if (NULL != handle->resp_object)
253 json_decref (handle->resp_object);
254 if (NULL != handle->timeout_task)
255 GNUNET_SCHEDULER_cancel (handle->timeout_task);
256 if (NULL != handle->identity_handle)
257 GNUNET_IDENTITY_disconnect (handle->identity_handle);
258 if (NULL != handle->attr_it)
259 GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
260 if (NULL != handle->ticket_it)
261 GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
262 if (NULL != handle->idp)
263 GNUNET_RECLAIM_disconnect (handle->idp);
264 if (NULL != handle->url)
265 GNUNET_free (handle->url);
266 if (NULL != handle->emsg)
267 GNUNET_free (handle->emsg);
268 if (NULL != handle->attr_list)
270 for (claim_entry = handle->attr_list->list_head; NULL != claim_entry;)
272 claim_tmp = claim_entry;
273 claim_entry = claim_entry->next;
274 GNUNET_free (claim_tmp->claim);
275 GNUNET_free (claim_tmp);
277 GNUNET_free (handle->attr_list);
279 for (ego_entry = handle->ego_head; NULL != ego_entry;)
282 ego_entry = ego_entry->next;
283 GNUNET_free (ego_tmp->identifier);
284 GNUNET_free (ego_tmp->keystring);
285 GNUNET_free (ego_tmp);
287 GNUNET_free (handle);
292 cleanup_handle_delayed (void *cls)
294 cleanup_handle (cls);
299 * Task run on error, sends error message. Cleans up everything.
301 * @param cls the `struct RequestHandle`
306 struct RequestHandle *handle = cls;
307 struct MHD_Response *resp;
310 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", handle->emsg);
311 if (0 == handle->response_code)
313 handle->response_code = MHD_HTTP_BAD_REQUEST;
315 resp = GNUNET_REST_create_response (json_error);
316 MHD_add_response_header (resp, "Content-Type", "application/json");
317 handle->proc (handle->proc_cls, resp, handle->response_code);
318 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
319 GNUNET_free (json_error);
324 * Task run on timeout, sends error message. Cleans up everything.
326 * @param cls the `struct RequestHandle`
329 do_timeout (void *cls)
331 struct RequestHandle *handle = cls;
333 handle->timeout_task = NULL;
339 collect_error_cb (void *cls)
341 struct RequestHandle *handle = cls;
348 finished_cont (void *cls, int32_t success, const char *emsg)
350 struct RequestHandle *handle = cls;
351 struct MHD_Response *resp;
353 resp = GNUNET_REST_create_response (emsg);
354 if (GNUNET_OK != success)
356 GNUNET_SCHEDULER_add_now (&do_error, handle);
359 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
360 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
365 * Return attributes for identity
367 * @param cls the request handle
370 return_response (void *cls)
373 struct RequestHandle *handle = cls;
374 struct MHD_Response *resp;
376 result_str = json_dumps (handle->resp_object, 0);
377 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
378 resp = GNUNET_REST_create_response (result_str);
379 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
380 GNUNET_free (result_str);
381 cleanup_handle (handle);
386 collect_finished_cb (void *cls)
388 struct RequestHandle *handle = cls;
391 handle->attr_it = NULL;
392 handle->ticket_it = NULL;
393 GNUNET_SCHEDULER_add_now (&return_response, handle);
398 * Collect all attributes for an ego
402 ticket_collect (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
404 json_t *json_resource;
405 struct RequestHandle *handle = cls;
409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
410 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(uint64_t));
411 json_resource = json_object ();
413 json_array_append (handle->resp_object, json_resource);
416 GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
418 GNUNET_CRYPTO_EcdsaPublicKey));
419 value = json_string (tmp);
420 json_object_set_new (json_resource, "issuer", value);
423 GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
425 GNUNET_CRYPTO_EcdsaPublicKey));
426 value = json_string (tmp);
427 json_object_set_new (json_resource, "audience", value);
429 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(uint64_t));
430 value = json_string (tmp);
431 json_object_set_new (json_resource, "rnd", value);
433 GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it);
438 * List tickets for identity request
440 * @param con_handle the connection handle
442 * @param cls the RequestHandle
445 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
449 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
450 struct RequestHandle *handle = cls;
451 struct EgoEntry *ego_entry;
454 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
455 "Getting tickets for %s.\n",
457 if (strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= strlen (handle->url))
459 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
460 GNUNET_SCHEDULER_add_now (&do_error, handle);
463 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
465 for (ego_entry = handle->ego_head; NULL != ego_entry;
466 ego_entry = ego_entry->next)
467 if (0 == strcmp (identity, ego_entry->identifier))
469 handle->resp_object = json_array ();
471 if (NULL == ego_entry)
474 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
475 GNUNET_SCHEDULER_add_now (&return_response, handle);
478 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
479 handle->idp = GNUNET_RECLAIM_connect (cfg);
481 GNUNET_RECLAIM_ticket_iteration_start (handle->idp,
487 &collect_finished_cb,
493 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
497 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
498 const char *identity;
499 struct RequestHandle *handle = cls;
500 struct EgoEntry *ego_entry;
501 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute;
502 struct GNUNET_TIME_Relative exp;
503 char term_data[handle->rest_handle->data_size + 1];
506 struct GNUNET_JSON_Specification attrspec[] =
507 { GNUNET_RECLAIM_JSON_spec_claim (&attribute), GNUNET_JSON_spec_end () };
509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
510 "Adding an attribute for %s.\n",
512 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
514 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
515 GNUNET_SCHEDULER_add_now (&do_error, handle);
518 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
520 for (ego_entry = handle->ego_head; NULL != ego_entry;
521 ego_entry = ego_entry->next)
522 if (0 == strcmp (identity, ego_entry->identifier))
525 if (NULL == ego_entry)
527 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
530 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
532 if (0 >= handle->rest_handle->data_size)
534 GNUNET_SCHEDULER_add_now (&do_error, handle);
538 term_data[handle->rest_handle->data_size] = '\0';
539 GNUNET_memcpy (term_data,
540 handle->rest_handle->data,
541 handle->rest_handle->data_size);
542 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
543 GNUNET_assert (GNUNET_OK ==
544 GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
545 json_decref (data_json);
546 if (NULL == attribute)
548 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
549 "Unable to parse attribute from %s\n",
551 GNUNET_SCHEDULER_add_now (&do_error, handle);
555 * New ID for attribute
557 if (0 == attribute->id)
559 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
560 handle->idp = GNUNET_RECLAIM_connect (cfg);
561 exp = GNUNET_TIME_UNIT_HOURS;
562 handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
568 GNUNET_JSON_parse_free (attrspec);
573 * Collect all attributes for an ego
577 attr_collect (void *cls,
578 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
579 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
581 struct RequestHandle *handle = cls;
587 if ((NULL == attr->name) || (NULL == attr->data))
589 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
593 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
595 tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
599 attr_obj = json_object ();
600 json_object_set_new (attr_obj, "value", json_string (tmp_value));
601 json_object_set_new (attr_obj, "name", json_string (attr->name));
602 type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
603 json_object_set_new (attr_obj, "type", json_string (type));
604 id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(uint64_t));
605 json_object_set_new (attr_obj, "id", json_string (id_str));
606 json_array_append (handle->resp_object, attr_obj);
607 json_decref (attr_obj);
608 GNUNET_free (tmp_value);
609 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
614 * List attributes for identity request
616 * @param con_handle the connection handle
618 * @param cls the RequestHandle
621 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
625 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
626 struct RequestHandle *handle = cls;
627 struct EgoEntry *ego_entry;
630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
631 "Getting attributes for %s.\n",
633 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
635 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
636 GNUNET_SCHEDULER_add_now (&do_error, handle);
639 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
641 for (ego_entry = handle->ego_head; NULL != ego_entry;
642 ego_entry = ego_entry->next)
643 if (0 == strcmp (identity, ego_entry->identifier))
645 handle->resp_object = json_array ();
648 if (NULL == ego_entry)
651 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
652 GNUNET_SCHEDULER_add_now (&return_response, handle);
655 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
656 handle->idp = GNUNET_RECLAIM_connect (cfg);
657 handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
663 &collect_finished_cb,
669 delete_finished_cb (void *cls, int32_t success, const char *emsg)
671 struct RequestHandle *handle = cls;
672 struct MHD_Response *resp;
674 resp = GNUNET_REST_create_response (emsg);
675 if (GNUNET_OK != success)
677 GNUNET_SCHEDULER_add_now (&do_error, handle);
680 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
681 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
686 * List attributes for identity request
688 * @param con_handle the connection handle
690 * @param cls the RequestHandle
693 delete_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
697 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
698 struct RequestHandle *handle = cls;
699 struct GNUNET_RECLAIM_ATTRIBUTE_Claim attr;
700 struct EgoEntry *ego_entry;
701 char *identity_id_str;
705 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attributes.\n");
706 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
708 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
709 GNUNET_SCHEDULER_add_now (&do_error, handle);
713 strdup (handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1);
714 identity = strtok (identity_id_str, "/");
715 id = strtok (NULL, "/");
716 if ((NULL == identity) || (NULL == id))
718 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
719 GNUNET_free (identity_id_str);
720 GNUNET_SCHEDULER_add_now (&do_error, handle);
724 for (ego_entry = handle->ego_head; NULL != ego_entry;
725 ego_entry = ego_entry->next)
726 if (0 == strcmp (identity, ego_entry->identifier))
728 handle->resp_object = json_array ();
729 if (NULL == ego_entry)
732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
733 GNUNET_free (identity_id_str);
734 GNUNET_SCHEDULER_add_now (&return_response, handle);
737 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
738 handle->idp = GNUNET_RECLAIM_connect (cfg);
739 memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_Claim));
740 GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(uint64_t));
742 handle->idp_op = GNUNET_RECLAIM_attribute_delete (handle->idp,
747 GNUNET_free (identity_id_str);
752 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
756 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
757 struct RequestHandle *handle = cls;
758 struct EgoEntry *ego_entry;
759 struct GNUNET_RECLAIM_Ticket *ticket = NULL;
760 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
761 char term_data[handle->rest_handle->data_size + 1];
764 struct GNUNET_JSON_Specification tktspec[] =
765 { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
767 if (0 >= handle->rest_handle->data_size)
769 GNUNET_SCHEDULER_add_now (&do_error, handle);
773 term_data[handle->rest_handle->data_size] = '\0';
774 GNUNET_memcpy (term_data,
775 handle->rest_handle->data,
776 handle->rest_handle->data_size);
777 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
778 if ((NULL == data_json) ||
779 (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)))
781 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
782 GNUNET_SCHEDULER_add_now (&do_error, handle);
783 GNUNET_JSON_parse_free (tktspec);
784 if (NULL != data_json)
785 json_decref (data_json);
788 json_decref (data_json);
791 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
792 "Unable to parse ticket from %s\n",
794 GNUNET_SCHEDULER_add_now (&do_error, handle);
798 for (ego_entry = handle->ego_head; NULL != ego_entry;
799 ego_entry = ego_entry->next)
801 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
802 if (0 == memcmp (&ticket->identity,
804 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
807 if (NULL == ego_entry)
809 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
810 GNUNET_JSON_parse_free (tktspec);
813 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
815 handle->idp = GNUNET_RECLAIM_connect (cfg);
816 handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
821 GNUNET_JSON_parse_free (tktspec);
826 consume_cont (void *cls,
827 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
828 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
830 struct RequestHandle *handle = cls;
834 if (NULL == identity)
836 GNUNET_SCHEDULER_add_now (&return_response, handle);
840 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
841 val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
846 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
847 "Failed to parse value for: %s\n",
851 value = json_string (val_str);
852 json_object_set_new (handle->resp_object, attr->name, value);
854 GNUNET_free (val_str);
859 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
863 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
864 struct RequestHandle *handle = cls;
865 struct EgoEntry *ego_entry;
866 struct GNUNET_RECLAIM_Ticket *ticket;
867 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
868 char term_data[handle->rest_handle->data_size + 1];
871 struct GNUNET_JSON_Specification tktspec[] =
872 { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
874 if (0 >= handle->rest_handle->data_size)
876 GNUNET_SCHEDULER_add_now (&do_error, handle);
880 term_data[handle->rest_handle->data_size] = '\0';
881 GNUNET_memcpy (term_data,
882 handle->rest_handle->data,
883 handle->rest_handle->data_size);
884 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
885 if (NULL == data_json)
887 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
888 "Unable to parse JSON Object from %s\n",
890 GNUNET_SCHEDULER_add_now (&do_error, handle);
893 if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL))
895 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
896 GNUNET_SCHEDULER_add_now (&do_error, handle);
897 GNUNET_JSON_parse_free (tktspec);
898 json_decref (data_json);
901 for (ego_entry = handle->ego_head; NULL != ego_entry;
902 ego_entry = ego_entry->next)
904 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
905 if (0 == memcmp (&ticket->audience,
907 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
910 if (NULL == ego_entry)
912 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
913 GNUNET_JSON_parse_free (tktspec);
916 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
917 handle->resp_object = json_object ();
918 handle->idp = GNUNET_RECLAIM_connect (cfg);
919 handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
924 GNUNET_JSON_parse_free (tktspec);
929 * Respond to OPTIONS request
931 * @param con_handle the connection handle
933 * @param cls the RequestHandle
936 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
940 struct MHD_Response *resp;
941 struct RequestHandle *handle = cls;
943 // For now, independent of path return all options
944 resp = GNUNET_REST_create_response (NULL);
945 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
946 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
947 cleanup_handle (handle);
953 * Handle rest request
955 * @param handle the request handle
958 init_cont (struct RequestHandle *handle)
960 struct GNUNET_REST_RequestHandlerError err;
961 static const struct GNUNET_REST_RequestHandler handlers[] =
962 { { MHD_HTTP_METHOD_GET,
963 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
964 &list_attribute_cont },
965 { MHD_HTTP_METHOD_POST,
966 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
967 &add_attribute_cont },
968 { MHD_HTTP_METHOD_DELETE,
969 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
970 &delete_attribute_cont },
971 { MHD_HTTP_METHOD_GET,
972 GNUNET_REST_API_NS_IDENTITY_TICKETS,
973 &list_tickets_cont },
974 { MHD_HTTP_METHOD_POST,
975 GNUNET_REST_API_NS_IDENTITY_REVOKE,
976 &revoke_ticket_cont },
977 { MHD_HTTP_METHOD_POST,
978 GNUNET_REST_API_NS_IDENTITY_CONSUME,
979 &consume_ticket_cont },
980 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, &options_cont },
981 GNUNET_REST_HANDLER_END };
984 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
986 handle->response_code = err.error_code;
987 GNUNET_SCHEDULER_add_now (&do_error, handle);
993 * If listing is enabled, prints information about the egos.
995 * This function is initially called for all egos and then again
996 * whenever a ego's identifier changes or if it is deleted. At the
997 * end of the initial pass over all egos, the function is once called
998 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
999 * be invoked in the future or that there was an error.
1001 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1002 * this function is only called ONCE, and 'NULL' being passed in
1003 * 'ego' does indicate an error (i.e. name is taken or no default
1004 * value is known). If 'ego' is non-NULL and if '*ctx'
1005 * is set in those callbacks, the value WILL be passed to a subsequent
1006 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1007 * that one was not NULL).
1009 * When an identity is renamed, this function is called with the
1010 * (known) ego but the NEW identifier.
1012 * When an identity is deleted, this function is called with the
1013 * (known) ego and "NULL" for the 'identifier'. In this case,
1014 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1017 * @param cls closure
1018 * @param ego ego handle
1019 * @param ctx context for application to store data for this ego
1020 * (during the lifetime of this process, initially NULL)
1021 * @param identifier identifier assigned by the user for this ego,
1022 * NULL if the user just deleted the ego and it
1023 * must thus no longer be used
1026 list_ego (void *cls,
1027 struct GNUNET_IDENTITY_Ego *ego,
1029 const char *identifier)
1031 struct RequestHandle *handle = cls;
1032 struct EgoEntry *ego_entry;
1033 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1035 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1037 handle->state = ID_REST_STATE_POST_INIT;
1041 if (ID_REST_STATE_INIT == handle->state)
1043 ego_entry = GNUNET_new (struct EgoEntry);
1044 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1045 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1046 ego_entry->ego = ego;
1047 ego_entry->identifier = GNUNET_strdup (identifier);
1048 GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
1056 rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1057 GNUNET_REST_ResultProcessor proc,
1060 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1062 handle->response_code = 0;
1063 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1064 handle->proc_cls = proc_cls;
1065 handle->proc = proc;
1066 handle->state = ID_REST_STATE_INIT;
1067 handle->rest_handle = rest_handle;
1069 handle->url = GNUNET_strdup (rest_handle->url);
1070 if (handle->url[strlen (handle->url) - 1] == '/')
1071 handle->url[strlen (handle->url) - 1] = '\0';
1072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1073 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
1074 handle->timeout_task =
1075 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
1076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1081 * Entry point for the plugin.
1083 * @param cls Config info
1084 * @return NULL on error, otherwise the plugin context
1087 libgnunet_plugin_rest_reclaim_init (void *cls)
1089 static struct Plugin plugin;
1090 struct GNUNET_REST_Plugin *api;
1093 if (NULL != plugin.cfg)
1094 return NULL; /* can only initialize once! */
1095 memset (&plugin, 0, sizeof(struct Plugin));
1097 api = GNUNET_new (struct GNUNET_REST_Plugin);
1099 api->name = GNUNET_REST_API_NS_RECLAIM;
1100 api->process_request = &rest_identity_process_request;
1101 GNUNET_asprintf (&allow_methods,
1102 "%s, %s, %s, %s, %s",
1103 MHD_HTTP_METHOD_GET,
1104 MHD_HTTP_METHOD_POST,
1105 MHD_HTTP_METHOD_PUT,
1106 MHD_HTTP_METHOD_DELETE,
1107 MHD_HTTP_METHOD_OPTIONS);
1109 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1110 _ ("Identity Provider REST API initialized\n"));
1116 * Exit point from the plugin.
1118 * @param cls the plugin context (as returned by "init")
1119 * @return always NULL
1122 libgnunet_plugin_rest_reclaim_done (void *cls)
1124 struct GNUNET_REST_Plugin *api = cls;
1125 struct Plugin *plugin = api->cls;
1129 GNUNET_free_non_null (allow_methods);
1131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1132 "Identity Provider REST plugin is finished\n");
1137 /* end of plugin_rest_reclaim.c */