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) {
268 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;) {
278 ego_entry = ego_entry->next;
279 GNUNET_free (ego_tmp->identifier);
280 GNUNET_free (ego_tmp->keystring);
281 GNUNET_free (ego_tmp);
283 if (NULL != handle->attr_it) {
284 GNUNET_free (handle->attr_it);
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) {
310 handle->response_code = MHD_HTTP_BAD_REQUEST;
312 resp = GNUNET_REST_create_response (json_error);
313 MHD_add_response_header (resp, "Content-Type", "application/json");
314 handle->proc (handle->proc_cls, resp, handle->response_code);
315 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
316 GNUNET_free (json_error);
321 * Task run on timeout, sends error message. Cleans up everything.
323 * @param cls the `struct RequestHandle`
326 do_timeout (void *cls)
328 struct RequestHandle *handle = cls;
330 handle->timeout_task = NULL;
336 collect_error_cb (void *cls)
338 struct RequestHandle *handle = cls;
344 finished_cont (void *cls, int32_t success, const char *emsg)
346 struct RequestHandle *handle = cls;
347 struct MHD_Response *resp;
349 resp = GNUNET_REST_create_response (emsg);
350 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;
384 handle->attr_it = NULL;
385 handle->ticket_it = NULL;
386 GNUNET_SCHEDULER_add_now (&return_response, handle);
391 * Collect all attributes for an ego
395 ticket_collect (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
397 json_t *json_resource;
398 struct RequestHandle *handle = cls;
402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
403 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof (uint64_t));
404 json_resource = json_object ();
406 json_array_append (handle->resp_object, json_resource);
408 tmp = GNUNET_STRINGS_data_to_string_alloc (
409 &ticket->identity, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
410 value = json_string (tmp);
411 json_object_set_new (json_resource, "issuer", value);
413 tmp = GNUNET_STRINGS_data_to_string_alloc (
414 &ticket->audience, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
415 value = json_string (tmp);
416 json_object_set_new (json_resource, "audience", value);
418 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof (uint64_t));
419 value = json_string (tmp);
420 json_object_set_new (json_resource, "rnd", value);
422 GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it);
427 * List tickets for identity request
429 * @param con_handle the connection handle
431 * @param cls the RequestHandle
434 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
435 const char *url, void *cls)
437 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
438 struct RequestHandle *handle = cls;
439 struct EgoEntry *ego_entry;
442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
444 if (strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= strlen (handle->url)) {
445 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
446 GNUNET_SCHEDULER_add_now (&do_error, handle);
449 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
451 for (ego_entry = handle->ego_head; NULL != ego_entry;
452 ego_entry = ego_entry->next)
453 if (0 == strcmp (identity, ego_entry->identifier))
455 handle->resp_object = json_array ();
457 if (NULL == ego_entry) {
459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
460 GNUNET_SCHEDULER_add_now (&return_response, handle);
463 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
464 handle->idp = GNUNET_RECLAIM_connect (cfg);
465 handle->ticket_it = GNUNET_RECLAIM_ticket_iteration_start (
466 handle->idp, priv_key, &collect_error_cb, handle, &ticket_collect, handle,
467 &collect_finished_cb, handle);
472 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
473 const char *url, void *cls)
475 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
476 const char *identity;
477 struct RequestHandle *handle = cls;
478 struct EgoEntry *ego_entry;
479 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute;
480 struct GNUNET_TIME_Relative exp;
481 char term_data[handle->rest_handle->data_size + 1];
484 struct GNUNET_JSON_Specification attrspec[] = {
485 GNUNET_RECLAIM_JSON_spec_claim (&attribute), GNUNET_JSON_spec_end ()};
487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
489 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url)) {
490 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
491 GNUNET_SCHEDULER_add_now (&do_error, handle);
494 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
496 for (ego_entry = handle->ego_head; NULL != ego_entry;
497 ego_entry = ego_entry->next)
498 if (0 == strcmp (identity, ego_entry->identifier))
501 if (NULL == ego_entry) {
502 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
505 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
507 if (0 >= handle->rest_handle->data_size) {
508 GNUNET_SCHEDULER_add_now (&do_error, handle);
512 term_data[handle->rest_handle->data_size] = '\0';
513 GNUNET_memcpy (term_data, handle->rest_handle->data,
514 handle->rest_handle->data_size);
515 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
516 GNUNET_assert (GNUNET_OK ==
517 GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
518 json_decref (data_json);
519 if (NULL == attribute) {
520 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to parse attribute from %s\n",
522 GNUNET_SCHEDULER_add_now (&do_error, handle);
526 * New ID for attribute
528 if (0 == attribute->id)
530 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
531 handle->idp = GNUNET_RECLAIM_connect (cfg);
532 exp = GNUNET_TIME_UNIT_HOURS;
533 handle->idp_op = GNUNET_RECLAIM_attribute_store (
534 handle->idp, identity_priv, attribute, &exp, &finished_cont, handle);
535 GNUNET_JSON_parse_free (attrspec);
540 * Collect all attributes for an ego
544 attr_collect (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
545 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
547 struct RequestHandle *handle = cls;
553 if ((NULL == attr->name) || (NULL == attr->data)) {
554 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
560 tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, attr->data,
563 attr_obj = json_object ();
564 json_object_set_new (attr_obj, "value", json_string (tmp_value));
565 json_object_set_new (attr_obj, "name", json_string (attr->name));
566 type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
567 json_object_set_new (attr_obj, "type", json_string (type));
568 id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof (uint64_t));
569 json_object_set_new (attr_obj, "id", json_string (id_str));
570 json_array_append (handle->resp_object, attr_obj);
571 json_decref (attr_obj);
572 GNUNET_free (tmp_value);
573 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
578 * List attributes for identity request
580 * @param con_handle the connection handle
582 * @param cls the RequestHandle
585 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
586 const char *url, void *cls)
588 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
589 struct RequestHandle *handle = cls;
590 struct EgoEntry *ego_entry;
593 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
595 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url)) {
596 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
597 GNUNET_SCHEDULER_add_now (&do_error, handle);
600 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
602 for (ego_entry = handle->ego_head; NULL != ego_entry;
603 ego_entry = ego_entry->next)
604 if (0 == strcmp (identity, ego_entry->identifier))
606 handle->resp_object = json_array ();
609 if (NULL == ego_entry) {
611 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
612 GNUNET_SCHEDULER_add_now (&return_response, handle);
615 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
616 handle->idp = GNUNET_RECLAIM_connect (cfg);
617 handle->attr_it = GNUNET_RECLAIM_get_attributes_start (
618 handle->idp, priv_key, &collect_error_cb, handle, &attr_collect, handle,
619 &collect_finished_cb, handle);
624 delete_finished_cb (void *cls, int32_t success, const char *emsg)
626 struct RequestHandle *handle = cls;
627 struct MHD_Response *resp;
629 resp = GNUNET_REST_create_response (emsg);
630 if (GNUNET_OK != success) {
631 GNUNET_SCHEDULER_add_now (&do_error, handle);
634 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
635 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
640 * List attributes for identity request
642 * @param con_handle the connection handle
644 * @param cls the RequestHandle
647 delete_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
648 const char *url, void *cls)
650 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
651 struct RequestHandle *handle = cls;
652 struct GNUNET_RECLAIM_ATTRIBUTE_Claim attr;
653 struct EgoEntry *ego_entry;
654 char *identity_id_str;
658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attributes.\n");
659 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url)) {
660 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
661 GNUNET_SCHEDULER_add_now (&do_error, handle);
665 strdup (handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1);
666 identity = strtok (identity_id_str, "/");
667 id = strtok (NULL, "/");
668 if ((NULL == identity) || (NULL == id)) {
669 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
670 GNUNET_free (identity_id_str);
671 GNUNET_SCHEDULER_add_now (&do_error, handle);
675 for (ego_entry = handle->ego_head; NULL != ego_entry;
676 ego_entry = ego_entry->next)
677 if (0 == strcmp (identity, ego_entry->identifier))
679 handle->resp_object = json_array ();
680 if (NULL == ego_entry) {
682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
683 GNUNET_free (identity_id_str);
684 GNUNET_SCHEDULER_add_now (&return_response, handle);
687 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
688 handle->idp = GNUNET_RECLAIM_connect (cfg);
689 memset (&attr, 0, sizeof (struct GNUNET_RECLAIM_ATTRIBUTE_Claim));
690 GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof (uint64_t));
692 handle->idp_op = GNUNET_RECLAIM_attribute_delete (
693 handle->idp, priv_key, &attr, &delete_finished_cb, handle);
694 GNUNET_free (identity_id_str);
699 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
700 const char *url, void *cls)
702 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
703 struct RequestHandle *handle = cls;
704 struct EgoEntry *ego_entry;
705 struct GNUNET_RECLAIM_Ticket *ticket;
706 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
707 char term_data[handle->rest_handle->data_size + 1];
710 struct GNUNET_JSON_Specification tktspec[] = {
711 GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end ()};
713 if (0 >= handle->rest_handle->data_size) {
714 GNUNET_SCHEDULER_add_now (&do_error, handle);
718 term_data[handle->rest_handle->data_size] = '\0';
719 GNUNET_memcpy (term_data, handle->rest_handle->data,
720 handle->rest_handle->data_size);
721 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
722 if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)) {
723 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
724 GNUNET_SCHEDULER_add_now (&do_error, handle);
725 GNUNET_JSON_parse_free (tktspec);
726 json_decref (data_json);
729 json_decref (data_json);
730 if (NULL == ticket) {
731 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to parse ticket from %s\n",
733 GNUNET_SCHEDULER_add_now (&do_error, handle);
737 for (ego_entry = handle->ego_head; NULL != ego_entry;
738 ego_entry = ego_entry->next) {
739 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
740 if (0 == memcmp (&ticket->identity, &tmp_pk,
741 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
744 if (NULL == ego_entry) {
745 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
746 GNUNET_JSON_parse_free (tktspec);
749 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
751 handle->idp = GNUNET_RECLAIM_connect (cfg);
752 handle->idp_op = GNUNET_RECLAIM_ticket_revoke (
753 handle->idp, identity_priv, ticket, &finished_cont, handle);
754 GNUNET_JSON_parse_free (tktspec);
758 consume_cont (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
759 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
761 struct RequestHandle *handle = cls;
765 if (NULL == identity) {
766 GNUNET_SCHEDULER_add_now (&return_response, handle);
770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
771 val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, attr->data,
773 if (NULL == val_str) {
774 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to parse value for: %s\n",
778 value = json_string (val_str);
779 json_object_set_new (handle->resp_object, attr->name, value);
781 GNUNET_free (val_str);
785 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
786 const char *url, void *cls)
788 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
789 struct RequestHandle *handle = cls;
790 struct EgoEntry *ego_entry;
791 struct GNUNET_RECLAIM_Ticket *ticket;
792 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
793 char term_data[handle->rest_handle->data_size + 1];
796 struct GNUNET_JSON_Specification tktspec[] = {
797 GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end ()};
799 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, handle->rest_handle->data,
806 handle->rest_handle->data_size);
807 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
808 if (NULL == data_json) {
809 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
810 "Unable to parse JSON Object from %s\n", term_data);
811 GNUNET_SCHEDULER_add_now (&do_error, handle);
814 if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)) {
815 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
816 GNUNET_SCHEDULER_add_now (&do_error, handle);
817 GNUNET_JSON_parse_free (tktspec);
818 json_decref (data_json);
821 for (ego_entry = handle->ego_head; NULL != ego_entry;
822 ego_entry = ego_entry->next) {
823 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
824 if (0 == memcmp (&ticket->audience, &tmp_pk,
825 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
828 if (NULL == ego_entry) {
829 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
830 GNUNET_JSON_parse_free (tktspec);
833 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
834 handle->resp_object = json_object ();
835 handle->idp = GNUNET_RECLAIM_connect (cfg);
836 handle->idp_op = GNUNET_RECLAIM_ticket_consume (
837 handle->idp, identity_priv, ticket, &consume_cont, handle);
838 GNUNET_JSON_parse_free (tktspec);
843 * Respond to OPTIONS request
845 * @param con_handle the connection handle
847 * @param cls the RequestHandle
850 options_cont (struct GNUNET_REST_RequestHandle *con_handle, const char *url,
853 struct MHD_Response *resp;
854 struct RequestHandle *handle = cls;
856 // For now, independent of path return all options
857 resp = GNUNET_REST_create_response (NULL);
858 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
859 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
860 cleanup_handle (handle);
865 * Handle rest request
867 * @param handle the request handle
870 init_cont (struct RequestHandle *handle)
872 struct GNUNET_REST_RequestHandlerError err;
873 static const struct GNUNET_REST_RequestHandler handlers[] = {
874 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
875 &list_attribute_cont},
876 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
877 &add_attribute_cont},
878 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
879 &delete_attribute_cont},
880 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS,
882 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE,
883 &revoke_ticket_cont},
884 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME,
885 &consume_ticket_cont},
886 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, &options_cont},
887 GNUNET_REST_HANDLER_END};
889 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, handlers,
891 handle->response_code = err.error_code;
892 GNUNET_SCHEDULER_add_now (&do_error, handle);
897 * If listing is enabled, prints information about the egos.
899 * This function is initially called for all egos and then again
900 * whenever a ego's identifier changes or if it is deleted. At the
901 * end of the initial pass over all egos, the function is once called
902 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
903 * be invoked in the future or that there was an error.
905 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
906 * this function is only called ONCE, and 'NULL' being passed in
907 * 'ego' does indicate an error (i.e. name is taken or no default
908 * value is known). If 'ego' is non-NULL and if '*ctx'
909 * is set in those callbacks, the value WILL be passed to a subsequent
910 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
911 * that one was not NULL).
913 * When an identity is renamed, this function is called with the
914 * (known) ego but the NEW identifier.
916 * When an identity is deleted, this function is called with the
917 * (known) ego and "NULL" for the 'identifier'. In this case,
918 * the 'ego' is henceforth invalid (and the 'ctx' should also be
922 * @param ego ego handle
923 * @param ctx context for application to store data for this ego
924 * (during the lifetime of this process, initially NULL)
925 * @param identifier identifier assigned by the user for this ego,
926 * NULL if the user just deleted the ego and it
927 * must thus no longer be used
930 list_ego (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx,
931 const char *identifier)
933 struct RequestHandle *handle = cls;
934 struct EgoEntry *ego_entry;
935 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
937 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state)) {
938 handle->state = ID_REST_STATE_POST_INIT;
942 if (ID_REST_STATE_INIT == handle->state) {
943 ego_entry = GNUNET_new (struct EgoEntry);
944 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
945 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
946 ego_entry->ego = ego;
947 ego_entry->identifier = GNUNET_strdup (identifier);
948 GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head, handle->ego_tail,
954 rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
955 GNUNET_REST_ResultProcessor proc, void *proc_cls)
957 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
958 handle->response_code = 0;
959 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
960 handle->proc_cls = proc_cls;
962 handle->state = ID_REST_STATE_INIT;
963 handle->rest_handle = rest_handle;
965 handle->url = GNUNET_strdup (rest_handle->url);
966 if (handle->url[strlen (handle->url) - 1] == '/')
967 handle->url[strlen (handle->url) - 1] = '\0';
968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
969 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
970 handle->timeout_task =
971 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
972 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
976 * Entry point for the plugin.
978 * @param cls Config info
979 * @return NULL on error, otherwise the plugin context
982 libgnunet_plugin_rest_reclaim_init (void *cls)
984 static struct Plugin plugin;
985 struct GNUNET_REST_Plugin *api;
988 if (NULL != plugin.cfg)
989 return NULL; /* can only initialize once! */
990 memset (&plugin, 0, sizeof (struct Plugin));
992 api = GNUNET_new (struct GNUNET_REST_Plugin);
994 api->name = GNUNET_REST_API_NS_RECLAIM;
995 api->process_request = &rest_identity_process_request;
996 GNUNET_asprintf (&allow_methods, "%s, %s, %s, %s, %s", MHD_HTTP_METHOD_GET,
997 MHD_HTTP_METHOD_POST, MHD_HTTP_METHOD_PUT,
998 MHD_HTTP_METHOD_DELETE, MHD_HTTP_METHOD_OPTIONS);
1000 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1001 _ ("Identity Provider REST API initialized\n"));
1007 * Exit point from the plugin.
1009 * @param cls the plugin context (as returned by "init")
1010 * @return always NULL
1013 libgnunet_plugin_rest_reclaim_done (void *cls)
1015 struct GNUNET_REST_Plugin *api = cls;
1016 struct Plugin *plugin = api->cls;
1019 GNUNET_free_non_null (allow_methods);
1021 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1022 "Identity Provider REST plugin is finished\n");
1026 /* end of plugin_rest_reclaim.c */