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
29 #include "microhttpd.h"
33 #include "gnunet_gns_service.h"
34 #include "gnunet_gnsrecord_lib.h"
35 #include "gnunet_identity_service.h"
36 #include "gnunet_namestore_service.h"
37 #include "gnunet_reclaim_attribute_lib.h"
38 #include "gnunet_reclaim_service.h"
39 #include "gnunet_rest_lib.h"
40 #include "gnunet_rest_plugin.h"
41 #include "gnunet_signatures.h"
42 #include "json_reclaim.h"
46 #define GNUNET_REST_API_NS_RECLAIM "/reclaim"
51 #define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/reclaim/attributes"
56 #define GNUNET_REST_API_NS_IDENTITY_TICKETS "/reclaim/tickets"
61 #define GNUNET_REST_API_NS_IDENTITY_REVOKE "/reclaim/revoke"
66 #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/reclaim/consume"
69 * State while collecting all egos
71 #define ID_REST_STATE_INIT 0
74 * Done collecting egos
76 #define ID_REST_STATE_POST_INIT 1
79 * The configuration handle
81 const struct GNUNET_CONFIGURATION_Handle *cfg;
84 * HTTP methods allows for this plugin
86 static char *allow_methods;
89 * @brief struct returned by the initialization function of the plugin
93 const struct GNUNET_CONFIGURATION_Handle *cfg;
104 struct EgoEntry *next;
109 struct EgoEntry *prev;
124 struct GNUNET_IDENTITY_Ego *ego;
133 struct EgoEntry *ego_head;
138 struct EgoEntry *ego_tail;
143 struct EgoEntry *ego_entry;
146 * Pointer to ego private key
148 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
151 * The processing state
156 * Handle to Identity service.
158 struct GNUNET_IDENTITY_Handle *identity_handle;
163 struct GNUNET_REST_RequestHandle *rest_handle;
166 * Handle to NAMESTORE
168 struct GNUNET_NAMESTORE_Handle *namestore_handle;
171 * Iterator for NAMESTORE
173 struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
176 * Attribute claim list
178 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list;
183 struct GNUNET_IDENTITY_Operation *op;
188 struct GNUNET_RECLAIM_Handle *idp;
193 struct GNUNET_RECLAIM_Operation *idp_op;
198 struct GNUNET_RECLAIM_AttributeIterator *attr_it;
203 struct GNUNET_RECLAIM_TicketIterator *ticket_it;
208 struct GNUNET_RECLAIM_Ticket ticket;
211 * Desired timeout for the lookup (default is no timeout).
213 struct GNUNET_TIME_Relative timeout;
216 * ID of a task associated with the resolution process.
218 struct GNUNET_SCHEDULER_Task *timeout_task;
221 * The plugin result processor
223 GNUNET_REST_ResultProcessor proc;
226 * The closure of the result processor
236 * Error response message
252 * Cleanup lookup handle
253 * @param handle Handle to clean up
256 cleanup_handle (struct RequestHandle *handle)
258 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry;
259 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp;
260 struct EgoEntry *ego_entry;
261 struct EgoEntry *ego_tmp;
262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
263 if (NULL != handle->resp_object)
264 json_decref (handle->resp_object);
265 if (NULL != handle->timeout_task)
266 GNUNET_SCHEDULER_cancel (handle->timeout_task);
267 if (NULL != handle->identity_handle)
268 GNUNET_IDENTITY_disconnect (handle->identity_handle);
269 if (NULL != handle->attr_it)
270 GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
271 if (NULL != handle->ticket_it)
272 GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
273 if (NULL != handle->idp)
274 GNUNET_RECLAIM_disconnect (handle->idp);
275 if (NULL != handle->url)
276 GNUNET_free (handle->url);
277 if (NULL != handle->emsg)
278 GNUNET_free (handle->emsg);
279 if (NULL != handle->namestore_handle)
280 GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
281 if (NULL != handle->attr_list) {
282 for (claim_entry = handle->attr_list->list_head; NULL != claim_entry;) {
283 claim_tmp = claim_entry;
284 claim_entry = claim_entry->next;
285 GNUNET_free (claim_tmp->claim);
286 GNUNET_free (claim_tmp);
288 GNUNET_free (handle->attr_list);
290 for (ego_entry = handle->ego_head; NULL != ego_entry;) {
292 ego_entry = ego_entry->next;
293 GNUNET_free (ego_tmp->identifier);
294 GNUNET_free (ego_tmp->keystring);
295 GNUNET_free (ego_tmp);
297 if (NULL != handle->attr_it) {
298 GNUNET_free (handle->attr_it);
300 GNUNET_free (handle);
304 cleanup_handle_delayed (void *cls)
306 cleanup_handle (cls);
311 * Task run on error, sends error message. Cleans up everything.
313 * @param cls the `struct RequestHandle`
318 struct RequestHandle *handle = cls;
319 struct MHD_Response *resp;
322 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", handle->emsg);
323 if (0 == handle->response_code) {
324 handle->response_code = MHD_HTTP_BAD_REQUEST;
326 resp = GNUNET_REST_create_response (json_error);
327 MHD_add_response_header (resp, "Content-Type", "application/json");
328 handle->proc (handle->proc_cls, resp, handle->response_code);
329 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
330 GNUNET_free (json_error);
335 * Task run on timeout, sends error message. Cleans up everything.
337 * @param cls the `struct RequestHandle`
340 do_timeout (void *cls)
342 struct RequestHandle *handle = cls;
344 handle->timeout_task = NULL;
350 collect_error_cb (void *cls)
352 struct RequestHandle *handle = cls;
358 finished_cont (void *cls, int32_t success, const char *emsg)
360 struct RequestHandle *handle = cls;
361 struct MHD_Response *resp;
363 resp = GNUNET_REST_create_response (emsg);
364 if (GNUNET_OK != success) {
365 GNUNET_SCHEDULER_add_now (&do_error, handle);
368 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
369 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
374 * Return attributes for identity
376 * @param cls the request handle
379 return_response (void *cls)
382 struct RequestHandle *handle = cls;
383 struct MHD_Response *resp;
385 result_str = json_dumps (handle->resp_object, 0);
386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
387 resp = GNUNET_REST_create_response (result_str);
388 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
389 GNUNET_free (result_str);
390 cleanup_handle (handle);
394 collect_finished_cb (void *cls)
396 struct RequestHandle *handle = cls;
398 handle->attr_it = NULL;
399 handle->ticket_it = NULL;
400 GNUNET_SCHEDULER_add_now (&return_response, handle);
405 * Collect all attributes for an ego
409 ticket_collect (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
411 json_t *json_resource;
412 struct RequestHandle *handle = cls;
416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
417 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof (uint64_t));
418 json_resource = json_object ();
420 json_array_append (handle->resp_object, json_resource);
422 tmp = GNUNET_STRINGS_data_to_string_alloc (
423 &ticket->identity, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
424 value = json_string (tmp);
425 json_object_set_new (json_resource, "issuer", value);
427 tmp = GNUNET_STRINGS_data_to_string_alloc (
428 &ticket->audience, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
429 value = json_string (tmp);
430 json_object_set_new (json_resource, "audience", value);
432 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof (uint64_t));
433 value = json_string (tmp);
434 json_object_set_new (json_resource, "rnd", value);
436 GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it);
441 * List tickets for identity request
443 * @param con_handle the connection handle
445 * @param cls the RequestHandle
448 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
449 const char *url, void *cls)
451 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
452 struct RequestHandle *handle = cls;
453 struct EgoEntry *ego_entry;
456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
458 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) {
473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
474 GNUNET_SCHEDULER_add_now (&return_response, handle);
477 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
478 handle->idp = GNUNET_RECLAIM_connect (cfg);
479 handle->ticket_it = GNUNET_RECLAIM_ticket_iteration_start (
480 handle->idp, priv_key, &collect_error_cb, handle, &ticket_collect, handle,
481 &collect_finished_cb, handle);
486 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
487 const char *url, void *cls)
489 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
490 const char *identity;
491 struct RequestHandle *handle = cls;
492 struct EgoEntry *ego_entry;
493 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute;
494 struct GNUNET_TIME_Relative exp;
495 char term_data[handle->rest_handle->data_size + 1];
498 struct GNUNET_JSON_Specification attrspec[] = {
499 GNUNET_RECLAIM_JSON_spec_claim (&attribute), GNUNET_JSON_spec_end ()};
501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
503 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url)) {
504 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
505 GNUNET_SCHEDULER_add_now (&do_error, handle);
508 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
510 for (ego_entry = handle->ego_head; NULL != ego_entry;
511 ego_entry = ego_entry->next)
512 if (0 == strcmp (identity, ego_entry->identifier))
515 if (NULL == ego_entry) {
516 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
519 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
521 if (0 >= handle->rest_handle->data_size) {
522 GNUNET_SCHEDULER_add_now (&do_error, handle);
526 term_data[handle->rest_handle->data_size] = '\0';
527 GNUNET_memcpy (term_data, handle->rest_handle->data,
528 handle->rest_handle->data_size);
529 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
530 GNUNET_assert (GNUNET_OK ==
531 GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
532 json_decref (data_json);
533 if (NULL == attribute) {
534 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to parse attribute from %s\n",
536 GNUNET_SCHEDULER_add_now (&do_error, handle);
540 * New ID for attribute
542 if (0 == attribute->id)
544 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
545 handle->idp = GNUNET_RECLAIM_connect (cfg);
546 exp = GNUNET_TIME_UNIT_HOURS;
547 handle->idp_op = GNUNET_RECLAIM_attribute_store (
548 handle->idp, identity_priv, attribute, &exp, &finished_cont, handle);
549 GNUNET_JSON_parse_free (attrspec);
554 * Collect all attributes for an ego
558 attr_collect (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
559 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
561 struct RequestHandle *handle = cls;
567 if ((NULL == attr->name) || (NULL == attr->data)) {
568 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
572 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
574 tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, attr->data,
577 attr_obj = json_object ();
578 json_object_set_new (attr_obj, "value", json_string (tmp_value));
579 json_object_set_new (attr_obj, "name", json_string (attr->name));
580 type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
581 json_object_set_new (attr_obj, "type", json_string (type));
582 id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof (uint64_t));
583 json_object_set_new (attr_obj, "id", json_string (id_str));
584 json_array_append (handle->resp_object, attr_obj);
585 json_decref (attr_obj);
586 GNUNET_free (tmp_value);
587 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
592 * List attributes for identity request
594 * @param con_handle the connection handle
596 * @param cls the RequestHandle
599 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
600 const char *url, void *cls)
602 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
603 struct RequestHandle *handle = cls;
604 struct EgoEntry *ego_entry;
607 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
609 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url)) {
610 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
611 GNUNET_SCHEDULER_add_now (&do_error, handle);
614 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
616 for (ego_entry = handle->ego_head; NULL != ego_entry;
617 ego_entry = ego_entry->next)
618 if (0 == strcmp (identity, ego_entry->identifier))
620 handle->resp_object = json_array ();
623 if (NULL == ego_entry) {
625 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
626 GNUNET_SCHEDULER_add_now (&return_response, handle);
629 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
630 handle->idp = GNUNET_RECLAIM_connect (cfg);
631 handle->attr_it = GNUNET_RECLAIM_get_attributes_start (
632 handle->idp, priv_key, &collect_error_cb, handle, &attr_collect, handle,
633 &collect_finished_cb, handle);
638 delete_finished_cb (void *cls, int32_t success, const char *emsg)
640 struct RequestHandle *handle = cls;
641 struct MHD_Response *resp;
643 resp = GNUNET_REST_create_response (emsg);
644 if (GNUNET_OK != success) {
645 GNUNET_SCHEDULER_add_now (&do_error, handle);
648 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
649 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
654 * List attributes for identity request
656 * @param con_handle the connection handle
658 * @param cls the RequestHandle
661 delete_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
662 const char *url, void *cls)
664 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
665 struct RequestHandle *handle = cls;
666 struct GNUNET_RECLAIM_ATTRIBUTE_Claim attr;
667 struct EgoEntry *ego_entry;
668 char *identity_id_str;
672 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attributes.\n");
673 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url)) {
674 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
675 GNUNET_SCHEDULER_add_now (&do_error, handle);
679 strdup (handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1);
680 identity = strtok (identity_id_str, "/");
681 id = strtok (NULL, "/");
682 if ((NULL == identity) || (NULL == id)) {
683 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
684 GNUNET_free (identity_id_str);
685 GNUNET_SCHEDULER_add_now (&do_error, handle);
689 for (ego_entry = handle->ego_head; NULL != ego_entry;
690 ego_entry = ego_entry->next)
691 if (0 == strcmp (identity, ego_entry->identifier))
693 handle->resp_object = json_array ();
694 if (NULL == ego_entry) {
696 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
697 GNUNET_free (identity_id_str);
698 GNUNET_SCHEDULER_add_now (&return_response, handle);
701 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
702 handle->idp = GNUNET_RECLAIM_connect (cfg);
703 memset (&attr, 0, sizeof (struct GNUNET_RECLAIM_ATTRIBUTE_Claim));
704 GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof (uint64_t));
706 handle->idp_op = GNUNET_RECLAIM_attribute_delete (
707 handle->idp, priv_key, &attr, &delete_finished_cb, handle);
708 GNUNET_free (identity_id_str);
713 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
714 const char *url, void *cls)
716 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
717 struct RequestHandle *handle = cls;
718 struct EgoEntry *ego_entry;
719 struct GNUNET_RECLAIM_Ticket *ticket;
720 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
721 char term_data[handle->rest_handle->data_size + 1];
724 struct GNUNET_JSON_Specification tktspec[] = {
725 GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end ()};
727 if (0 >= handle->rest_handle->data_size) {
728 GNUNET_SCHEDULER_add_now (&do_error, handle);
732 term_data[handle->rest_handle->data_size] = '\0';
733 GNUNET_memcpy (term_data, handle->rest_handle->data,
734 handle->rest_handle->data_size);
735 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
736 GNUNET_assert (GNUNET_OK ==
737 GNUNET_JSON_parse (data_json, tktspec, NULL, NULL));
738 json_decref (data_json);
739 if (NULL == ticket) {
740 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to parse ticket from %s\n",
742 GNUNET_SCHEDULER_add_now (&do_error, handle);
745 if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)) {
746 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
747 GNUNET_SCHEDULER_add_now (&do_error, handle);
748 GNUNET_JSON_parse_free (tktspec);
749 json_decref (data_json);
753 for (ego_entry = handle->ego_head; NULL != ego_entry;
754 ego_entry = ego_entry->next) {
755 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
756 if (0 == memcmp (&ticket->identity, &tmp_pk,
757 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
760 if (NULL == ego_entry) {
761 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
762 GNUNET_JSON_parse_free (tktspec);
765 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
767 handle->idp = GNUNET_RECLAIM_connect (cfg);
768 handle->idp_op = GNUNET_RECLAIM_ticket_revoke (
769 handle->idp, identity_priv, ticket, &finished_cont, handle);
770 GNUNET_JSON_parse_free (tktspec);
774 consume_cont (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
775 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
777 struct RequestHandle *handle = cls;
781 if (NULL == identity) {
782 GNUNET_SCHEDULER_add_now (&return_response, handle);
786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
787 val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, attr->data,
789 if (NULL == val_str) {
790 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to parse value for: %s\n",
794 value = json_string (val_str);
795 json_object_set_new (handle->resp_object, attr->name, value);
797 GNUNET_free (val_str);
801 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
802 const char *url, void *cls)
804 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
805 struct RequestHandle *handle = cls;
806 struct EgoEntry *ego_entry;
807 struct GNUNET_RECLAIM_Ticket *ticket;
808 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
809 char term_data[handle->rest_handle->data_size + 1];
812 struct GNUNET_JSON_Specification tktspec[] = {
813 GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end ()};
815 if (0 >= handle->rest_handle->data_size) {
816 GNUNET_SCHEDULER_add_now (&do_error, handle);
820 term_data[handle->rest_handle->data_size] = '\0';
821 GNUNET_memcpy (term_data, handle->rest_handle->data,
822 handle->rest_handle->data_size);
823 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
824 if (NULL == data_json) {
825 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
826 "Unable to parse JSON Object from %s\n", term_data);
827 GNUNET_SCHEDULER_add_now (&do_error, handle);
830 if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)) {
831 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
832 GNUNET_SCHEDULER_add_now (&do_error, handle);
833 GNUNET_JSON_parse_free (tktspec);
834 json_decref (data_json);
837 for (ego_entry = handle->ego_head; NULL != ego_entry;
838 ego_entry = ego_entry->next) {
839 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
840 if (0 == memcmp (&ticket->audience, &tmp_pk,
841 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
844 if (NULL == ego_entry) {
845 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
846 GNUNET_JSON_parse_free (tktspec);
849 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
850 handle->resp_object = json_object ();
851 handle->idp = GNUNET_RECLAIM_connect (cfg);
852 handle->idp_op = GNUNET_RECLAIM_ticket_consume (
853 handle->idp, identity_priv, ticket, &consume_cont, handle);
854 GNUNET_JSON_parse_free (tktspec);
859 * Respond to OPTIONS request
861 * @param con_handle the connection handle
863 * @param cls the RequestHandle
866 options_cont (struct GNUNET_REST_RequestHandle *con_handle, const char *url,
869 struct MHD_Response *resp;
870 struct RequestHandle *handle = cls;
872 // For now, independent of path return all options
873 resp = GNUNET_REST_create_response (NULL);
874 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
875 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
876 cleanup_handle (handle);
881 * Handle rest request
883 * @param handle the request handle
886 init_cont (struct RequestHandle *handle)
888 struct GNUNET_REST_RequestHandlerError err;
889 static const struct GNUNET_REST_RequestHandler handlers[] = {
890 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
891 &list_attribute_cont},
892 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
893 &add_attribute_cont},
894 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
895 &delete_attribute_cont},
896 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS,
898 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE,
899 &revoke_ticket_cont},
900 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME,
901 &consume_ticket_cont},
902 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, &options_cont},
903 GNUNET_REST_HANDLER_END};
905 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, handlers,
907 handle->response_code = err.error_code;
908 GNUNET_SCHEDULER_add_now (&do_error, handle);
913 * If listing is enabled, prints information about the egos.
915 * This function is initially called for all egos and then again
916 * whenever a ego's identifier changes or if it is deleted. At the
917 * end of the initial pass over all egos, the function is once called
918 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
919 * be invoked in the future or that there was an error.
921 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
922 * this function is only called ONCE, and 'NULL' being passed in
923 * 'ego' does indicate an error (i.e. name is taken or no default
924 * value is known). If 'ego' is non-NULL and if '*ctx'
925 * is set in those callbacks, the value WILL be passed to a subsequent
926 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
927 * that one was not NULL).
929 * When an identity is renamed, this function is called with the
930 * (known) ego but the NEW identifier.
932 * When an identity is deleted, this function is called with the
933 * (known) ego and "NULL" for the 'identifier'. In this case,
934 * the 'ego' is henceforth invalid (and the 'ctx' should also be
938 * @param ego ego handle
939 * @param ctx context for application to store data for this ego
940 * (during the lifetime of this process, initially NULL)
941 * @param identifier identifier assigned by the user for this ego,
942 * NULL if the user just deleted the ego and it
943 * must thus no longer be used
946 list_ego (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx,
947 const char *identifier)
949 struct RequestHandle *handle = cls;
950 struct EgoEntry *ego_entry;
951 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
953 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state)) {
954 handle->state = ID_REST_STATE_POST_INIT;
958 if (ID_REST_STATE_INIT == handle->state) {
959 ego_entry = GNUNET_new (struct EgoEntry);
960 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
961 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
962 ego_entry->ego = ego;
963 ego_entry->identifier = GNUNET_strdup (identifier);
964 GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head, handle->ego_tail,
970 rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
971 GNUNET_REST_ResultProcessor proc, void *proc_cls)
973 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
974 handle->response_code = 0;
975 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
976 handle->proc_cls = proc_cls;
978 handle->state = ID_REST_STATE_INIT;
979 handle->rest_handle = rest_handle;
981 handle->url = GNUNET_strdup (rest_handle->url);
982 if (handle->url[strlen (handle->url) - 1] == '/')
983 handle->url[strlen (handle->url) - 1] = '\0';
984 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
985 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
986 handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
987 handle->timeout_task =
988 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
989 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
993 * Entry point for the plugin.
995 * @param cls Config info
996 * @return NULL on error, otherwise the plugin context
999 libgnunet_plugin_rest_reclaim_init (void *cls)
1001 static struct Plugin plugin;
1002 struct GNUNET_REST_Plugin *api;
1005 if (NULL != plugin.cfg)
1006 return NULL; /* can only initialize once! */
1007 memset (&plugin, 0, sizeof (struct Plugin));
1009 api = GNUNET_new (struct GNUNET_REST_Plugin);
1011 api->name = GNUNET_REST_API_NS_RECLAIM;
1012 api->process_request = &rest_identity_process_request;
1013 GNUNET_asprintf (&allow_methods, "%s, %s, %s, %s, %s", MHD_HTTP_METHOD_GET,
1014 MHD_HTTP_METHOD_POST, MHD_HTTP_METHOD_PUT,
1015 MHD_HTTP_METHOD_DELETE, MHD_HTTP_METHOD_OPTIONS);
1017 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1018 _ ("Identity Provider REST API initialized\n"));
1024 * Exit point from the plugin.
1026 * @param cls the plugin context (as returned by "init")
1027 * @return always NULL
1030 libgnunet_plugin_rest_reclaim_done (void *cls)
1032 struct GNUNET_REST_Plugin *api = cls;
1033 struct Plugin *plugin = api->cls;
1036 GNUNET_free_non_null (allow_methods);
1038 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1039 "Identity Provider REST plugin is finished\n");
1043 /* end of plugin_rest_reclaim.c */