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
90 const struct GNUNET_CONFIGURATION_Handle *cfg;
100 struct EgoEntry *next;
105 struct EgoEntry *prev;
120 struct GNUNET_IDENTITY_Ego *ego;
124 struct RequestHandle {
128 struct EgoEntry *ego_head;
133 struct EgoEntry *ego_tail;
138 struct EgoEntry *ego_entry;
141 * Pointer to ego private key
143 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
146 * The processing state
151 * Handle to Identity service.
153 struct GNUNET_IDENTITY_Handle *identity_handle;
158 struct GNUNET_REST_RequestHandle *rest_handle;
161 * Attribute claim list
163 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list;
168 struct GNUNET_IDENTITY_Operation *op;
173 struct GNUNET_RECLAIM_Handle *idp;
178 struct GNUNET_RECLAIM_Operation *idp_op;
183 struct GNUNET_RECLAIM_AttributeIterator *attr_it;
188 struct GNUNET_RECLAIM_TicketIterator *ticket_it;
193 struct GNUNET_RECLAIM_Ticket ticket;
196 * Desired timeout for the lookup (default is no timeout).
198 struct GNUNET_TIME_Relative timeout;
201 * ID of a task associated with the resolution process.
203 struct GNUNET_SCHEDULER_Task *timeout_task;
206 * The plugin result processor
208 GNUNET_REST_ResultProcessor proc;
211 * The closure of the result processor
221 * Error response message
237 * Cleanup lookup handle
238 * @param handle Handle to clean up
241 cleanup_handle(struct RequestHandle *handle)
243 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry;
244 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp;
245 struct EgoEntry *ego_entry;
246 struct EgoEntry *ego_tmp;
248 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
249 if (NULL != handle->resp_object)
250 json_decref(handle->resp_object);
251 if (NULL != handle->timeout_task)
252 GNUNET_SCHEDULER_cancel(handle->timeout_task);
253 if (NULL != handle->identity_handle)
254 GNUNET_IDENTITY_disconnect(handle->identity_handle);
255 if (NULL != handle->attr_it)
256 GNUNET_RECLAIM_get_attributes_stop(handle->attr_it);
257 if (NULL != handle->ticket_it)
258 GNUNET_RECLAIM_ticket_iteration_stop(handle->ticket_it);
259 if (NULL != handle->idp)
260 GNUNET_RECLAIM_disconnect(handle->idp);
261 if (NULL != handle->url)
262 GNUNET_free(handle->url);
263 if (NULL != handle->emsg)
264 GNUNET_free(handle->emsg);
265 if (NULL != handle->attr_list)
267 for (claim_entry = handle->attr_list->list_head; NULL != claim_entry;)
269 claim_tmp = claim_entry;
270 claim_entry = claim_entry->next;
271 GNUNET_free(claim_tmp->claim);
272 GNUNET_free(claim_tmp);
274 GNUNET_free(handle->attr_list);
276 for (ego_entry = handle->ego_head; NULL != ego_entry;)
279 ego_entry = ego_entry->next;
280 GNUNET_free(ego_tmp->identifier);
281 GNUNET_free(ego_tmp->keystring);
282 GNUNET_free(ego_tmp);
288 cleanup_handle_delayed(void *cls)
295 * Task run on error, sends error message. Cleans up everything.
297 * @param cls the `struct RequestHandle`
302 struct RequestHandle *handle = cls;
303 struct MHD_Response *resp;
306 GNUNET_asprintf(&json_error, "{ \"error\" : \"%s\" }", handle->emsg);
307 if (0 == handle->response_code)
309 handle->response_code = MHD_HTTP_BAD_REQUEST;
311 resp = GNUNET_REST_create_response(json_error);
312 MHD_add_response_header(resp, "Content-Type", "application/json");
313 handle->proc(handle->proc_cls, resp, handle->response_code);
314 GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle);
315 GNUNET_free(json_error);
320 * Task run on timeout, sends error message. Cleans up everything.
322 * @param cls the `struct RequestHandle`
325 do_timeout(void *cls)
327 struct RequestHandle *handle = cls;
329 handle->timeout_task = NULL;
335 collect_error_cb(void *cls)
337 struct RequestHandle *handle = cls;
343 finished_cont(void *cls, int32_t success, const char *emsg)
345 struct RequestHandle *handle = cls;
346 struct MHD_Response *resp;
348 resp = GNUNET_REST_create_response(emsg);
349 if (GNUNET_OK != success)
351 GNUNET_SCHEDULER_add_now(&do_error, handle);
354 handle->proc(handle->proc_cls, resp, MHD_HTTP_OK);
355 GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle);
360 * Return attributes for identity
362 * @param cls the request handle
365 return_response(void *cls)
368 struct RequestHandle *handle = cls;
369 struct MHD_Response *resp;
371 result_str = json_dumps(handle->resp_object, 0);
372 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
373 resp = GNUNET_REST_create_response(result_str);
374 handle->proc(handle->proc_cls, resp, MHD_HTTP_OK);
375 GNUNET_free(result_str);
376 cleanup_handle(handle);
380 collect_finished_cb(void *cls)
382 struct RequestHandle *handle = cls;
385 handle->attr_it = NULL;
386 handle->ticket_it = NULL;
387 GNUNET_SCHEDULER_add_now(&return_response, handle);
392 * Collect all attributes for an ego
396 ticket_collect(void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
398 json_t *json_resource;
399 struct RequestHandle *handle = cls;
403 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
404 tmp = GNUNET_STRINGS_data_to_string_alloc(&ticket->rnd, sizeof(uint64_t));
405 json_resource = json_object();
407 json_array_append(handle->resp_object, json_resource);
410 GNUNET_STRINGS_data_to_string_alloc(&ticket->identity,
412 GNUNET_CRYPTO_EcdsaPublicKey));
413 value = json_string(tmp);
414 json_object_set_new(json_resource, "issuer", value);
417 GNUNET_STRINGS_data_to_string_alloc(&ticket->audience,
419 GNUNET_CRYPTO_EcdsaPublicKey));
420 value = json_string(tmp);
421 json_object_set_new(json_resource, "audience", value);
423 tmp = GNUNET_STRINGS_data_to_string_alloc(&ticket->rnd, sizeof(uint64_t));
424 value = json_string(tmp);
425 json_object_set_new(json_resource, "rnd", value);
427 GNUNET_RECLAIM_ticket_iteration_next(handle->ticket_it);
432 * List tickets for identity request
434 * @param con_handle the connection handle
436 * @param cls the RequestHandle
439 list_tickets_cont(struct GNUNET_REST_RequestHandle *con_handle,
443 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
444 struct RequestHandle *handle = cls;
445 struct EgoEntry *ego_entry;
448 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
449 "Getting tickets for %s.\n",
451 if (strlen(GNUNET_REST_API_NS_IDENTITY_TICKETS) >= strlen(handle->url))
453 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
454 GNUNET_SCHEDULER_add_now(&do_error, handle);
457 identity = handle->url + strlen(GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
459 for (ego_entry = handle->ego_head; NULL != ego_entry;
460 ego_entry = ego_entry->next)
461 if (0 == strcmp(identity, ego_entry->identifier))
463 handle->resp_object = json_array();
465 if (NULL == ego_entry)
468 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
469 GNUNET_SCHEDULER_add_now(&return_response, handle);
472 priv_key = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
473 handle->idp = GNUNET_RECLAIM_connect(cfg);
475 GNUNET_RECLAIM_ticket_iteration_start(handle->idp,
481 &collect_finished_cb,
487 add_attribute_cont(struct GNUNET_REST_RequestHandle *con_handle,
491 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
492 const char *identity;
493 struct RequestHandle *handle = cls;
494 struct EgoEntry *ego_entry;
495 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute;
496 struct GNUNET_TIME_Relative exp;
497 char term_data[handle->rest_handle->data_size + 1];
500 struct GNUNET_JSON_Specification attrspec[] =
501 { GNUNET_RECLAIM_JSON_spec_claim(&attribute), GNUNET_JSON_spec_end() };
503 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
504 "Adding an attribute for %s.\n",
506 if (strlen(GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen(handle->url))
508 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
509 GNUNET_SCHEDULER_add_now(&do_error, handle);
512 identity = handle->url + strlen(GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
514 for (ego_entry = handle->ego_head; NULL != ego_entry;
515 ego_entry = ego_entry->next)
516 if (0 == strcmp(identity, ego_entry->identifier))
519 if (NULL == ego_entry)
521 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
524 identity_priv = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
526 if (0 >= handle->rest_handle->data_size)
528 GNUNET_SCHEDULER_add_now(&do_error, handle);
532 term_data[handle->rest_handle->data_size] = '\0';
533 GNUNET_memcpy(term_data,
534 handle->rest_handle->data,
535 handle->rest_handle->data_size);
536 data_json = json_loads(term_data, JSON_DECODE_ANY, &err);
537 GNUNET_assert(GNUNET_OK ==
538 GNUNET_JSON_parse(data_json, attrspec, NULL, NULL));
539 json_decref(data_json);
540 if (NULL == attribute)
542 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
543 "Unable to parse attribute from %s\n",
545 GNUNET_SCHEDULER_add_now(&do_error, handle);
549 * New ID for attribute
551 if (0 == attribute->id)
553 GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
554 handle->idp = GNUNET_RECLAIM_connect(cfg);
555 exp = GNUNET_TIME_UNIT_HOURS;
556 handle->idp_op = GNUNET_RECLAIM_attribute_store(handle->idp,
562 GNUNET_JSON_parse_free(attrspec);
567 * Collect all attributes for an ego
571 attr_collect(void *cls,
572 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
573 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
575 struct RequestHandle *handle = cls;
581 if ((NULL == attr->name) || (NULL == attr->data))
583 GNUNET_RECLAIM_get_attributes_next(handle->attr_it);
587 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
589 tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string(attr->type,
593 attr_obj = json_object();
594 json_object_set_new(attr_obj, "value", json_string(tmp_value));
595 json_object_set_new(attr_obj, "name", json_string(attr->name));
596 type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename(attr->type);
597 json_object_set_new(attr_obj, "type", json_string(type));
598 id_str = GNUNET_STRINGS_data_to_string_alloc(&attr->id, sizeof(uint64_t));
599 json_object_set_new(attr_obj, "id", json_string(id_str));
600 json_array_append(handle->resp_object, attr_obj);
601 json_decref(attr_obj);
602 GNUNET_free(tmp_value);
603 GNUNET_RECLAIM_get_attributes_next(handle->attr_it);
608 * List attributes for identity request
610 * @param con_handle the connection handle
612 * @param cls the RequestHandle
615 list_attribute_cont(struct GNUNET_REST_RequestHandle *con_handle,
619 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
620 struct RequestHandle *handle = cls;
621 struct EgoEntry *ego_entry;
624 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
625 "Getting attributes for %s.\n",
627 if (strlen(GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen(handle->url))
629 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
630 GNUNET_SCHEDULER_add_now(&do_error, handle);
633 identity = handle->url + strlen(GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
635 for (ego_entry = handle->ego_head; NULL != ego_entry;
636 ego_entry = ego_entry->next)
637 if (0 == strcmp(identity, ego_entry->identifier))
639 handle->resp_object = json_array();
642 if (NULL == ego_entry)
645 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
646 GNUNET_SCHEDULER_add_now(&return_response, handle);
649 priv_key = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
650 handle->idp = GNUNET_RECLAIM_connect(cfg);
651 handle->attr_it = GNUNET_RECLAIM_get_attributes_start(handle->idp,
657 &collect_finished_cb,
663 delete_finished_cb(void *cls, int32_t success, const char *emsg)
665 struct RequestHandle *handle = cls;
666 struct MHD_Response *resp;
668 resp = GNUNET_REST_create_response(emsg);
669 if (GNUNET_OK != success)
671 GNUNET_SCHEDULER_add_now(&do_error, handle);
674 handle->proc(handle->proc_cls, resp, MHD_HTTP_OK);
675 GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle);
680 * List attributes for identity request
682 * @param con_handle the connection handle
684 * @param cls the RequestHandle
687 delete_attribute_cont(struct GNUNET_REST_RequestHandle *con_handle,
691 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
692 struct RequestHandle *handle = cls;
693 struct GNUNET_RECLAIM_ATTRIBUTE_Claim attr;
694 struct EgoEntry *ego_entry;
695 char *identity_id_str;
699 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Deleting attributes.\n");
700 if (strlen(GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen(handle->url))
702 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
703 GNUNET_SCHEDULER_add_now(&do_error, handle);
707 strdup(handle->url + strlen(GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1);
708 identity = strtok(identity_id_str, "/");
709 id = strtok(NULL, "/");
710 if ((NULL == identity) || (NULL == id))
712 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
713 GNUNET_free(identity_id_str);
714 GNUNET_SCHEDULER_add_now(&do_error, handle);
718 for (ego_entry = handle->ego_head; NULL != ego_entry;
719 ego_entry = ego_entry->next)
720 if (0 == strcmp(identity, ego_entry->identifier))
722 handle->resp_object = json_array();
723 if (NULL == ego_entry)
726 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
727 GNUNET_free(identity_id_str);
728 GNUNET_SCHEDULER_add_now(&return_response, handle);
731 priv_key = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
732 handle->idp = GNUNET_RECLAIM_connect(cfg);
733 memset(&attr, 0, sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_Claim));
734 GNUNET_STRINGS_string_to_data(id, strlen(id), &attr.id, sizeof(uint64_t));
736 handle->idp_op = GNUNET_RECLAIM_attribute_delete(handle->idp,
741 GNUNET_free(identity_id_str);
746 revoke_ticket_cont(struct GNUNET_REST_RequestHandle *con_handle,
750 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
751 struct RequestHandle *handle = cls;
752 struct EgoEntry *ego_entry;
753 struct GNUNET_RECLAIM_Ticket *ticket = NULL;
754 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
755 char term_data[handle->rest_handle->data_size + 1];
758 struct GNUNET_JSON_Specification tktspec[] =
759 { GNUNET_RECLAIM_JSON_spec_ticket(&ticket), GNUNET_JSON_spec_end() };
761 if (0 >= handle->rest_handle->data_size)
763 GNUNET_SCHEDULER_add_now(&do_error, handle);
767 term_data[handle->rest_handle->data_size] = '\0';
768 GNUNET_memcpy(term_data,
769 handle->rest_handle->data,
770 handle->rest_handle->data_size);
771 data_json = json_loads(term_data, JSON_DECODE_ANY, &err);
772 if ((NULL == data_json) ||
773 (GNUNET_OK != GNUNET_JSON_parse(data_json, tktspec, NULL, NULL)))
775 handle->emsg = GNUNET_strdup("Not a ticket!\n");
776 GNUNET_SCHEDULER_add_now(&do_error, handle);
777 GNUNET_JSON_parse_free(tktspec);
778 if (NULL != data_json)
779 json_decref(data_json);
782 json_decref(data_json);
785 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
786 "Unable to parse ticket from %s\n",
788 GNUNET_SCHEDULER_add_now(&do_error, handle);
792 for (ego_entry = handle->ego_head; NULL != ego_entry;
793 ego_entry = ego_entry->next)
795 GNUNET_IDENTITY_ego_get_public_key(ego_entry->ego, &tmp_pk);
796 if (0 == memcmp(&ticket->identity,
798 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
801 if (NULL == ego_entry)
803 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
804 GNUNET_JSON_parse_free(tktspec);
807 identity_priv = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
809 handle->idp = GNUNET_RECLAIM_connect(cfg);
810 handle->idp_op = GNUNET_RECLAIM_ticket_revoke(handle->idp,
815 GNUNET_JSON_parse_free(tktspec);
819 consume_cont(void *cls,
820 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
821 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
823 struct RequestHandle *handle = cls;
827 if (NULL == identity)
829 GNUNET_SCHEDULER_add_now(&return_response, handle);
833 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
834 val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string(attr->type,
839 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
840 "Failed to parse value for: %s\n",
844 value = json_string(val_str);
845 json_object_set_new(handle->resp_object, attr->name, value);
847 GNUNET_free(val_str);
851 consume_ticket_cont(struct GNUNET_REST_RequestHandle *con_handle,
855 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
856 struct RequestHandle *handle = cls;
857 struct EgoEntry *ego_entry;
858 struct GNUNET_RECLAIM_Ticket *ticket;
859 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
860 char term_data[handle->rest_handle->data_size + 1];
863 struct GNUNET_JSON_Specification tktspec[] =
864 { GNUNET_RECLAIM_JSON_spec_ticket(&ticket), GNUNET_JSON_spec_end() };
866 if (0 >= handle->rest_handle->data_size)
868 GNUNET_SCHEDULER_add_now(&do_error, handle);
872 term_data[handle->rest_handle->data_size] = '\0';
873 GNUNET_memcpy(term_data,
874 handle->rest_handle->data,
875 handle->rest_handle->data_size);
876 data_json = json_loads(term_data, JSON_DECODE_ANY, &err);
877 if (NULL == data_json)
879 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
880 "Unable to parse JSON Object from %s\n",
882 GNUNET_SCHEDULER_add_now(&do_error, handle);
885 if (GNUNET_OK != GNUNET_JSON_parse(data_json, tktspec, NULL, NULL))
887 handle->emsg = GNUNET_strdup("Not a ticket!\n");
888 GNUNET_SCHEDULER_add_now(&do_error, handle);
889 GNUNET_JSON_parse_free(tktspec);
890 json_decref(data_json);
893 for (ego_entry = handle->ego_head; NULL != ego_entry;
894 ego_entry = ego_entry->next)
896 GNUNET_IDENTITY_ego_get_public_key(ego_entry->ego, &tmp_pk);
897 if (0 == memcmp(&ticket->audience,
899 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
902 if (NULL == ego_entry)
904 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
905 GNUNET_JSON_parse_free(tktspec);
908 identity_priv = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
909 handle->resp_object = json_object();
910 handle->idp = GNUNET_RECLAIM_connect(cfg);
911 handle->idp_op = GNUNET_RECLAIM_ticket_consume(handle->idp,
916 GNUNET_JSON_parse_free(tktspec);
921 * Respond to OPTIONS request
923 * @param con_handle the connection handle
925 * @param cls the RequestHandle
928 options_cont(struct GNUNET_REST_RequestHandle *con_handle,
932 struct MHD_Response *resp;
933 struct RequestHandle *handle = cls;
935 // For now, independent of path return all options
936 resp = GNUNET_REST_create_response(NULL);
937 MHD_add_response_header(resp, "Access-Control-Allow-Methods", allow_methods);
938 handle->proc(handle->proc_cls, resp, MHD_HTTP_OK);
939 cleanup_handle(handle);
944 * Handle rest request
946 * @param handle the request handle
949 init_cont(struct RequestHandle *handle)
951 struct GNUNET_REST_RequestHandlerError err;
952 static const struct GNUNET_REST_RequestHandler handlers[] =
953 { { MHD_HTTP_METHOD_GET,
954 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
955 &list_attribute_cont },
956 { MHD_HTTP_METHOD_POST,
957 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
958 &add_attribute_cont },
959 { MHD_HTTP_METHOD_DELETE,
960 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
961 &delete_attribute_cont },
962 { MHD_HTTP_METHOD_GET,
963 GNUNET_REST_API_NS_IDENTITY_TICKETS,
964 &list_tickets_cont },
965 { MHD_HTTP_METHOD_POST,
966 GNUNET_REST_API_NS_IDENTITY_REVOKE,
967 &revoke_ticket_cont },
968 { MHD_HTTP_METHOD_POST,
969 GNUNET_REST_API_NS_IDENTITY_CONSUME,
970 &consume_ticket_cont },
971 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, &options_cont },
972 GNUNET_REST_HANDLER_END };
975 GNUNET_REST_handle_request(handle->rest_handle, handlers, &err, handle))
977 handle->response_code = err.error_code;
978 GNUNET_SCHEDULER_add_now(&do_error, handle);
983 * If listing is enabled, prints information about the egos.
985 * This function is initially called for all egos and then again
986 * whenever a ego's identifier changes or if it is deleted. At the
987 * end of the initial pass over all egos, the function is once called
988 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
989 * be invoked in the future or that there was an error.
991 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
992 * this function is only called ONCE, and 'NULL' being passed in
993 * 'ego' does indicate an error (i.e. name is taken or no default
994 * value is known). If 'ego' is non-NULL and if '*ctx'
995 * is set in those callbacks, the value WILL be passed to a subsequent
996 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
997 * that one was not NULL).
999 * When an identity is renamed, this function is called with the
1000 * (known) ego but the NEW identifier.
1002 * When an identity is deleted, this function is called with the
1003 * (known) ego and "NULL" for the 'identifier'. In this case,
1004 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1007 * @param cls closure
1008 * @param ego ego handle
1009 * @param ctx context for application to store data for this ego
1010 * (during the lifetime of this process, initially NULL)
1011 * @param identifier identifier assigned by the user for this ego,
1012 * NULL if the user just deleted the ego and it
1013 * must thus no longer be used
1017 struct GNUNET_IDENTITY_Ego *ego,
1019 const char *identifier)
1021 struct RequestHandle *handle = cls;
1022 struct EgoEntry *ego_entry;
1023 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1025 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1027 handle->state = ID_REST_STATE_POST_INIT;
1031 if (ID_REST_STATE_INIT == handle->state)
1033 ego_entry = GNUNET_new(struct EgoEntry);
1034 GNUNET_IDENTITY_ego_get_public_key(ego, &pk);
1035 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string(&pk);
1036 ego_entry->ego = ego;
1037 ego_entry->identifier = GNUNET_strdup(identifier);
1038 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,
1045 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1046 GNUNET_REST_ResultProcessor proc,
1049 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;
1117 GNUNET_free_non_null(allow_methods);
1119 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1120 "Identity Provider REST plugin is finished\n");
1124 /* end of plugin_rest_reclaim.c */