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_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"
43 #define GNUNET_REST_API_NS_RECLAIM "/reclaim"
48 #define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/reclaim/attributes"
51 * Attestation namespace
53 #define GNUNET_REST_API_NS_RECLAIM_ATTESTATION "/reclaim/attestation"
58 #define GNUNET_REST_API_NS_IDENTITY_TICKETS "/reclaim/tickets"
63 #define GNUNET_REST_API_NS_IDENTITY_REVOKE "/reclaim/revoke"
68 #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/reclaim/consume"
71 * State while collecting all egos
73 #define ID_REST_STATE_INIT 0
76 * Done collecting egos
78 #define ID_REST_STATE_POST_INIT 1
81 * The configuration handle
83 const struct GNUNET_CONFIGURATION_Handle *cfg;
86 * HTTP methods allows for this plugin
88 static char *allow_methods;
91 * @brief struct returned by the initialization function of the plugin
95 const struct GNUNET_CONFIGURATION_Handle *cfg;
106 struct EgoEntry *next;
111 struct EgoEntry *prev;
126 struct GNUNET_IDENTITY_Ego *ego;
135 struct EgoEntry *ego_head;
140 struct EgoEntry *ego_tail;
145 struct EgoEntry *ego_entry;
148 * Pointer to ego private key
150 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
153 * The processing state
158 * Handle to Identity service.
160 struct GNUNET_IDENTITY_Handle *identity_handle;
165 struct GNUNET_REST_RequestHandle *rest_handle;
168 * Attribute claim list
170 struct GNUNET_RECLAIM_AttributeList *attr_list;
175 struct GNUNET_IDENTITY_Operation *op;
180 struct GNUNET_RECLAIM_Handle *idp;
185 struct GNUNET_RECLAIM_Operation *idp_op;
190 struct GNUNET_RECLAIM_AttributeIterator *attr_it;
195 struct GNUNET_RECLAIM_AttestationIterator *attest_it;
201 struct GNUNET_RECLAIM_TicketIterator *ticket_it;
206 struct GNUNET_RECLAIM_Ticket ticket;
209 * Desired timeout for the lookup (default is no timeout).
211 struct GNUNET_TIME_Relative timeout;
214 * ID of a task associated with the resolution process.
216 struct GNUNET_SCHEDULER_Task *timeout_task;
219 * The plugin result processor
221 GNUNET_REST_ResultProcessor proc;
224 * The closure of the result processor
234 * Error response message
250 * Cleanup lookup handle
251 * @param handle Handle to clean up
254 cleanup_handle (struct RequestHandle *handle)
256 struct EgoEntry *ego_entry;
257 struct EgoEntry *ego_tmp;
259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
260 if (NULL != handle->resp_object)
261 json_decref (handle->resp_object);
262 if (NULL != handle->timeout_task)
263 GNUNET_SCHEDULER_cancel (handle->timeout_task);
264 if (NULL != handle->identity_handle)
265 GNUNET_IDENTITY_disconnect (handle->identity_handle);
266 if (NULL != handle->attr_it)
267 GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
268 if (NULL != handle->attest_it)
269 GNUNET_RECLAIM_get_attestations_stop (handle->attest_it);
270 if (NULL != handle->ticket_it)
271 GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
272 if (NULL != handle->idp)
273 GNUNET_RECLAIM_disconnect (handle->idp);
274 if (NULL != handle->url)
275 GNUNET_free (handle->url);
276 if (NULL != handle->emsg)
277 GNUNET_free (handle->emsg);
278 if (NULL != handle->attr_list)
279 GNUNET_RECLAIM_attribute_list_destroy (handle->attr_list);
280 for (ego_entry = handle->ego_head; NULL != ego_entry;)
283 ego_entry = ego_entry->next;
284 GNUNET_free (ego_tmp->identifier);
285 GNUNET_free (ego_tmp->keystring);
286 GNUNET_free (ego_tmp);
288 GNUNET_free (handle);
293 cleanup_handle_delayed (void *cls)
295 cleanup_handle (cls);
300 * Task run on error, sends error message. Cleans up everything.
302 * @param cls the `struct RequestHandle`
307 struct RequestHandle *handle = cls;
308 struct MHD_Response *resp;
311 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", handle->emsg);
312 if (0 == handle->response_code)
314 handle->response_code = MHD_HTTP_BAD_REQUEST;
316 resp = GNUNET_REST_create_response (json_error);
317 MHD_add_response_header (resp, "Content-Type", "application/json");
318 handle->proc (handle->proc_cls, resp, handle->response_code);
319 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
320 GNUNET_free (json_error);
325 * Task run on timeout, sends error message. Cleans up everything.
327 * @param cls the `struct RequestHandle`
330 do_timeout (void *cls)
332 struct RequestHandle *handle = cls;
334 handle->timeout_task = NULL;
340 collect_error_cb (void *cls)
342 struct RequestHandle *handle = cls;
349 finished_cont (void *cls, int32_t success, const char *emsg)
351 struct RequestHandle *handle = cls;
352 struct MHD_Response *resp;
354 resp = GNUNET_REST_create_response (emsg);
355 if (GNUNET_OK != success)
357 GNUNET_SCHEDULER_add_now (&do_error, handle);
360 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
361 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
366 delete_finished_cb (void *cls, int32_t success, const char *emsg)
368 struct RequestHandle *handle = cls;
369 struct MHD_Response *resp;
371 resp = GNUNET_REST_create_response (emsg);
372 if (GNUNET_OK != success)
374 GNUNET_SCHEDULER_add_now (&do_error, handle);
377 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
378 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
383 * Return attributes for identity
385 * @param cls the request handle
388 return_response (void *cls)
391 struct RequestHandle *handle = cls;
392 struct MHD_Response *resp;
394 result_str = json_dumps (handle->resp_object, 0);
395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
396 resp = GNUNET_REST_create_response (result_str);
397 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
398 GNUNET_free (result_str);
399 cleanup_handle (handle);
404 collect_finished_cb (void *cls)
406 struct RequestHandle *handle = cls;
409 handle->attr_it = NULL;
410 handle->attest_it = NULL;
411 handle->ticket_it = NULL;
412 GNUNET_SCHEDULER_add_now (&return_response, handle);
417 * Collect all attributes for an ego
421 ticket_collect (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
423 json_t *json_resource;
424 struct RequestHandle *handle = cls;
428 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
429 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(ticket->rnd));
430 json_resource = json_object ();
432 json_array_append (handle->resp_object, json_resource);
435 GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
437 GNUNET_CRYPTO_EcdsaPublicKey));
438 value = json_string (tmp);
439 json_object_set_new (json_resource, "issuer", value);
442 GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
444 GNUNET_CRYPTO_EcdsaPublicKey));
445 value = json_string (tmp);
446 json_object_set_new (json_resource, "audience", value);
448 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(ticket->rnd));
449 value = json_string (tmp);
450 json_object_set_new (json_resource, "rnd", value);
452 GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it);
457 add_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
461 struct RequestHandle *handle = cls;
462 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
463 const char *identity;
464 struct EgoEntry *ego_entry;
465 struct GNUNET_RECLAIM_Attestation *attribute;
466 struct GNUNET_TIME_Relative exp;
467 char term_data[handle->rest_handle->data_size + 1];
470 struct GNUNET_JSON_Specification attrspec[] =
471 { GNUNET_RECLAIM_JSON_spec_claim_attest (&attribute),
472 GNUNET_JSON_spec_end () };
474 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
475 "Adding an attestation for %s.\n",
477 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
480 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
481 GNUNET_SCHEDULER_add_now (&do_error, handle);
484 identity = handle->url + strlen (
485 GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1;
487 for (ego_entry = handle->ego_head; NULL != ego_entry;
488 ego_entry = ego_entry->next)
489 if (0 == strcmp (identity, ego_entry->identifier))
492 if (NULL == ego_entry)
494 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
497 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
499 if (0 >= handle->rest_handle->data_size)
501 GNUNET_SCHEDULER_add_now (&do_error, handle);
505 term_data[handle->rest_handle->data_size] = '\0';
506 GNUNET_memcpy (term_data,
507 handle->rest_handle->data,
508 handle->rest_handle->data_size);
509 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
510 GNUNET_assert (GNUNET_OK ==
511 GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
512 json_decref (data_json);
513 if (NULL == attribute)
515 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
516 "Unable to parse attestation from %s\n",
518 GNUNET_SCHEDULER_add_now (&do_error, handle);
522 * New ID for attribute
524 if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id))
525 GNUNET_RECLAIM_id_generate (&attribute->id);
526 handle->idp = GNUNET_RECLAIM_connect (cfg);
527 exp = GNUNET_TIME_UNIT_HOURS;
528 handle->idp_op = GNUNET_RECLAIM_attestation_store (handle->idp,
534 GNUNET_JSON_parse_free (attrspec);
539 * Collect all attestations for an ego
543 attest_collect (void *cls,
544 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
545 const struct GNUNET_RECLAIM_Attestation *attest)
547 struct RequestHandle *handle = cls;
548 struct GNUNET_RECLAIM_AttributeList *attrs;
549 struct GNUNET_RECLAIM_AttributeListEntry *ale;
550 struct GNUNET_TIME_Absolute exp;
559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attestation: %s\n",
561 attrs = GNUNET_RECLAIM_attestation_get_attributes (attest);
562 issuer = GNUNET_RECLAIM_attestation_get_issuer (attest);
563 tmp_value = GNUNET_RECLAIM_attestation_value_to_string (attest->type,
566 attest_obj = json_object ();
567 json_object_set_new (attest_obj, "value", json_string (tmp_value));
568 json_object_set_new (attest_obj, "name", json_string (attest->name));
569 type = GNUNET_RECLAIM_attestation_number_to_typename (attest->type);
570 json_object_set_new (attest_obj, "type", json_string (type));
573 json_object_set_new (attest_obj, "issuer", json_string (issuer));
574 GNUNET_free (issuer);
576 if (GNUNET_OK == GNUNET_RECLAIM_attestation_get_expiration (attest,
579 json_object_set_new (attest_obj, "expiration", json_integer (exp.abs_value_us));
581 id_str = GNUNET_STRINGS_data_to_string_alloc (&attest->id,
583 json_object_set_new (attest_obj, "id", json_string (id_str));
584 GNUNET_free (tmp_value);
585 GNUNET_free (id_str);
588 json_t *attr_arr = json_array ();
589 for (ale = attrs->list_head; NULL != ale; ale = ale->next)
592 GNUNET_RECLAIM_attribute_value_to_string (ale->attribute->type,
593 ale->attribute->data,
594 ale->attribute->data_size);
595 attr_obj = json_object ();
596 json_object_set_new (attr_obj, "value", json_string (tmp_value));
597 json_object_set_new (attr_obj, "name", json_string (
598 ale->attribute->name));
600 json_object_set_new (attr_obj, "flag", json_string ("1")); //FIXME
601 type = GNUNET_RECLAIM_attribute_number_to_typename (ale->attribute->type);
602 json_object_set_new (attr_obj, "type", json_string (type));
603 json_object_set_new (attr_obj, "id", json_string (""));
604 json_object_set_new (attr_obj, "attestation", json_string (""));
605 json_array_append_new (attr_arr, attr_obj);
606 GNUNET_free (tmp_value);
608 json_object_set_new (attest_obj, "attributes", attr_arr);
610 json_array_append_new (handle->resp_object, attest_obj);
611 GNUNET_RECLAIM_attribute_list_destroy (attrs);
612 GNUNET_RECLAIM_get_attestations_next (handle->attest_it);
617 * Lists attestation for identity request
619 * @param con_handle the connection handle
621 * @param cls the RequestHandle
624 list_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
628 struct RequestHandle *handle = cls;
629 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
630 struct EgoEntry *ego_entry;
633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634 "Getting attestations for %s.\n",
636 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
639 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
640 GNUNET_SCHEDULER_add_now (&do_error, handle);
643 identity = handle->url + strlen (
644 GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1;
646 for (ego_entry = handle->ego_head; NULL != ego_entry;
647 ego_entry = ego_entry->next)
648 if (0 == strcmp (identity, ego_entry->identifier))
650 handle->resp_object = json_array ();
653 if (NULL == ego_entry)
656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
657 GNUNET_SCHEDULER_add_now (&return_response, handle);
660 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
661 handle->idp = GNUNET_RECLAIM_connect (cfg);
662 handle->attest_it = GNUNET_RECLAIM_get_attestations_start (handle->idp,
675 * Deletes attestation from an identity
677 * @param con_handle the connection handle
679 * @param cls the RequestHandle
682 delete_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
686 struct RequestHandle *handle = cls;
687 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
688 struct GNUNET_RECLAIM_Attestation attr;
689 struct EgoEntry *ego_entry;
690 char *identity_id_str;
694 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attestation.\n");
695 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
698 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
699 GNUNET_SCHEDULER_add_now (&do_error, handle);
703 strdup (handle->url + strlen (
704 GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1);
705 identity = strtok (identity_id_str, "/");
706 id = strtok (NULL, "/");
707 if ((NULL == identity) || (NULL == id))
709 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
710 GNUNET_free (identity_id_str);
711 GNUNET_SCHEDULER_add_now (&do_error, handle);
715 for (ego_entry = handle->ego_head; NULL != ego_entry;
716 ego_entry = ego_entry->next)
717 if (0 == strcmp (identity, ego_entry->identifier))
719 handle->resp_object = json_array ();
720 if (NULL == ego_entry)
723 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
724 GNUNET_free (identity_id_str);
725 GNUNET_SCHEDULER_add_now (&return_response, handle);
728 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
729 handle->idp = GNUNET_RECLAIM_connect (cfg);
730 memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Attestation));
731 GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
733 handle->idp_op = GNUNET_RECLAIM_attestation_delete (handle->idp,
738 GNUNET_free (identity_id_str);
743 * List tickets for identity request
745 * @param con_handle the connection handle
747 * @param cls the RequestHandle
750 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
754 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
755 struct RequestHandle *handle = cls;
756 struct EgoEntry *ego_entry;
759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
760 "Getting tickets for %s.\n",
762 if (strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= strlen (handle->url))
764 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
765 GNUNET_SCHEDULER_add_now (&do_error, handle);
768 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
770 for (ego_entry = handle->ego_head; NULL != ego_entry;
771 ego_entry = ego_entry->next)
772 if (0 == strcmp (identity, ego_entry->identifier))
774 handle->resp_object = json_array ();
776 if (NULL == ego_entry)
779 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
780 GNUNET_SCHEDULER_add_now (&return_response, handle);
783 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
784 handle->idp = GNUNET_RECLAIM_connect (cfg);
786 GNUNET_RECLAIM_ticket_iteration_start (handle->idp,
792 &collect_finished_cb,
798 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
802 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
803 const char *identity;
804 struct RequestHandle *handle = cls;
805 struct EgoEntry *ego_entry;
806 struct GNUNET_RECLAIM_Attribute *attribute;
807 struct GNUNET_TIME_Relative exp;
808 char term_data[handle->rest_handle->data_size + 1];
811 struct GNUNET_JSON_Specification attrspec[] =
812 { GNUNET_RECLAIM_JSON_spec_claim (&attribute), GNUNET_JSON_spec_end () };
814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
815 "Adding an attribute for %s.\n",
817 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
819 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
820 GNUNET_SCHEDULER_add_now (&do_error, handle);
823 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
825 for (ego_entry = handle->ego_head; NULL != ego_entry;
826 ego_entry = ego_entry->next)
827 if (0 == strcmp (identity, ego_entry->identifier))
830 if (NULL == ego_entry)
832 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
835 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
837 if (0 >= handle->rest_handle->data_size)
839 GNUNET_SCHEDULER_add_now (&do_error, handle);
843 term_data[handle->rest_handle->data_size] = '\0';
844 GNUNET_memcpy (term_data,
845 handle->rest_handle->data,
846 handle->rest_handle->data_size);
847 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
848 GNUNET_assert (GNUNET_OK ==
849 GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
850 json_decref (data_json);
851 if (NULL == attribute)
853 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
854 "Unable to parse attribute from %s\n",
856 GNUNET_SCHEDULER_add_now (&do_error, handle);
860 * New ID for attribute
862 if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id))
863 GNUNET_RECLAIM_id_generate (&attribute->id);
864 handle->idp = GNUNET_RECLAIM_connect (cfg);
865 exp = GNUNET_TIME_UNIT_HOURS;
866 handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
872 GNUNET_JSON_parse_free (attrspec);
877 * Parse a JWT and return the respective claim value as Attribute
879 * @param attest the jwt attestation
880 * @param claim the name of the claim in the JWT
882 * @return a GNUNET_RECLAIM_Attribute, containing the new value
884 struct GNUNET_RECLAIM_Attribute *
885 parse_jwt (const struct GNUNET_RECLAIM_Attestation *attest,
889 struct GNUNET_RECLAIM_Attribute *attr;
891 const char *type_str = NULL;
892 const char *val_str = NULL;
896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing JWT attributes.\n");
899 json_error_t *json_err = NULL;
901 jwt_string = GNUNET_RECLAIM_attestation_value_to_string (attest->type,
904 char *jwt_body = strtok (jwt_string, delim);
905 jwt_body = strtok (NULL, delim);
906 GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body),
907 (void **) &decoded_jwt);
908 json_val = json_loads (decoded_jwt, JSON_DECODE_ANY, json_err);
911 json_object_foreach (json_val, key, value) {
912 if (0 == strcasecmp (key,claim))
914 val_str = json_dumps (value, JSON_ENCODE_ANY);
918 type = GNUNET_RECLAIM_attribute_typename_to_number (type_str);
919 if (GNUNET_SYSERR == GNUNET_RECLAIM_attribute_string_to_value (type,val_str,
923 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
924 "Attribute value from JWT Parser invalid!\n");
925 GNUNET_RECLAIM_attribute_string_to_value (type,
926 "Error: Referenced Claim Name not Found",
929 attr = GNUNET_RECLAIM_attribute_new (claim, &attest->id,
930 type, data, data_size);
931 attr->id = attest->id;
936 attr = GNUNET_RECLAIM_attribute_new (claim, &attest->id,
937 type, data, data_size);
938 attr->id = attest->id;
946 * Collect all attributes for an ego
950 attr_collect (void *cls,
951 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
952 const struct GNUNET_RECLAIM_Attribute *attr)
954 struct RequestHandle *handle = cls;
960 tmp_value = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
963 attr_obj = json_object ();
964 json_object_set_new (attr_obj, "value", json_string (tmp_value));
965 json_object_set_new (attr_obj, "name", json_string (attr->name));
967 json_object_set_new (attr_obj, "flag", json_string ("1"));
968 type = GNUNET_RECLAIM_attribute_number_to_typename (attr->type);
969 json_object_set_new (attr_obj, "type", json_string (type));
970 id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id,
972 json_object_set_new (attr_obj, "id", json_string (id_str));
973 id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->attestation,
974 sizeof(attr->attestation));
975 json_object_set_new (attr_obj, "attestation", json_string (id_str));
976 json_array_append (handle->resp_object, attr_obj);
977 json_decref (attr_obj);
978 GNUNET_free (tmp_value);
979 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
984 * List attributes for identity request
986 * @param con_handle the connection handle
988 * @param cls the RequestHandle
991 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
995 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
996 struct RequestHandle *handle = cls;
997 struct EgoEntry *ego_entry;
1000 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1001 "Getting attributes for %s.\n",
1003 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1005 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1006 GNUNET_SCHEDULER_add_now (&do_error, handle);
1009 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
1011 for (ego_entry = handle->ego_head; NULL != ego_entry;
1012 ego_entry = ego_entry->next)
1013 if (0 == strcmp (identity, ego_entry->identifier))
1015 handle->resp_object = json_array ();
1018 if (NULL == ego_entry)
1021 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1022 GNUNET_SCHEDULER_add_now (&return_response, handle);
1025 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1026 handle->idp = GNUNET_RECLAIM_connect (cfg);
1027 handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
1033 &collect_finished_cb,
1039 * List attributes for identity request
1041 * @param con_handle the connection handle
1042 * @param url the url
1043 * @param cls the RequestHandle
1046 delete_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1050 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1051 struct RequestHandle *handle = cls;
1052 struct GNUNET_RECLAIM_Attribute attr;
1053 struct EgoEntry *ego_entry;
1054 char *identity_id_str;
1058 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attributes.\n");
1059 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1061 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1062 GNUNET_SCHEDULER_add_now (&do_error, handle);
1066 strdup (handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1);
1067 identity = strtok (identity_id_str, "/");
1068 id = strtok (NULL, "/");
1069 if ((NULL == identity) || (NULL == id))
1071 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
1072 GNUNET_free (identity_id_str);
1073 GNUNET_SCHEDULER_add_now (&do_error, handle);
1077 for (ego_entry = handle->ego_head; NULL != ego_entry;
1078 ego_entry = ego_entry->next)
1079 if (0 == strcmp (identity, ego_entry->identifier))
1081 handle->resp_object = json_array ();
1082 if (NULL == ego_entry)
1085 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1086 GNUNET_free (identity_id_str);
1087 GNUNET_SCHEDULER_add_now (&return_response, handle);
1090 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1091 handle->idp = GNUNET_RECLAIM_connect (cfg);
1092 memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Attribute));
1093 GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
1095 handle->idp_op = GNUNET_RECLAIM_attribute_delete (handle->idp,
1098 &delete_finished_cb,
1100 GNUNET_free (identity_id_str);
1105 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1109 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1110 struct RequestHandle *handle = cls;
1111 struct EgoEntry *ego_entry;
1112 struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1113 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1114 char term_data[handle->rest_handle->data_size + 1];
1117 struct GNUNET_JSON_Specification tktspec[] =
1118 { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1120 if (0 >= handle->rest_handle->data_size)
1122 GNUNET_SCHEDULER_add_now (&do_error, handle);
1126 term_data[handle->rest_handle->data_size] = '\0';
1127 GNUNET_memcpy (term_data,
1128 handle->rest_handle->data,
1129 handle->rest_handle->data_size);
1130 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1131 if ((NULL == data_json) ||
1132 (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)))
1134 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1135 GNUNET_SCHEDULER_add_now (&do_error, handle);
1136 GNUNET_JSON_parse_free (tktspec);
1137 if (NULL != data_json)
1138 json_decref (data_json);
1141 json_decref (data_json);
1144 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1145 "Unable to parse ticket from %s\n",
1147 GNUNET_SCHEDULER_add_now (&do_error, handle);
1151 for (ego_entry = handle->ego_head; NULL != ego_entry;
1152 ego_entry = ego_entry->next)
1154 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1155 if (0 == memcmp (&ticket->identity,
1157 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1160 if (NULL == ego_entry)
1162 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1163 GNUNET_JSON_parse_free (tktspec);
1166 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1168 handle->idp = GNUNET_RECLAIM_connect (cfg);
1169 handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
1174 GNUNET_JSON_parse_free (tktspec);
1179 consume_cont (void *cls,
1180 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1181 const struct GNUNET_RECLAIM_Attribute *attr,
1182 const struct GNUNET_RECLAIM_Attestation *attest)
1184 struct RequestHandle *handle = cls;
1188 if (NULL == identity)
1190 GNUNET_SCHEDULER_add_now (&return_response, handle);
1194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
1195 val_str = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
1198 if (NULL == val_str)
1200 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1201 "Failed to parse value for: %s\n",
1205 value = json_string (val_str);
1206 json_object_set_new (handle->resp_object, attr->name, value);
1207 json_decref (value);
1208 GNUNET_free (val_str);
1213 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1217 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1218 struct RequestHandle *handle = cls;
1219 struct EgoEntry *ego_entry;
1220 struct GNUNET_RECLAIM_Ticket *ticket;
1221 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1222 char term_data[handle->rest_handle->data_size + 1];
1225 struct GNUNET_JSON_Specification tktspec[] =
1226 { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1228 if (0 >= handle->rest_handle->data_size)
1230 GNUNET_SCHEDULER_add_now (&do_error, handle);
1234 term_data[handle->rest_handle->data_size] = '\0';
1235 GNUNET_memcpy (term_data,
1236 handle->rest_handle->data,
1237 handle->rest_handle->data_size);
1238 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1239 if (NULL == data_json)
1241 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1242 "Unable to parse JSON Object from %s\n",
1244 GNUNET_SCHEDULER_add_now (&do_error, handle);
1247 if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL))
1249 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1250 GNUNET_SCHEDULER_add_now (&do_error, handle);
1251 GNUNET_JSON_parse_free (tktspec);
1252 json_decref (data_json);
1255 for (ego_entry = handle->ego_head; NULL != ego_entry;
1256 ego_entry = ego_entry->next)
1258 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1259 if (0 == memcmp (&ticket->audience,
1261 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1264 if (NULL == ego_entry)
1266 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1267 GNUNET_JSON_parse_free (tktspec);
1270 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1271 handle->resp_object = json_object ();
1272 handle->idp = GNUNET_RECLAIM_connect (cfg);
1273 handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
1278 GNUNET_JSON_parse_free (tktspec);
1283 * Respond to OPTIONS request
1285 * @param con_handle the connection handle
1286 * @param url the url
1287 * @param cls the RequestHandle
1290 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1294 struct MHD_Response *resp;
1295 struct RequestHandle *handle = cls;
1297 // For now, independent of path return all options
1298 resp = GNUNET_REST_create_response (NULL);
1299 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
1300 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1301 cleanup_handle (handle);
1307 * Handle rest request
1309 * @param handle the request handle
1312 init_cont (struct RequestHandle *handle)
1314 struct GNUNET_REST_RequestHandlerError err;
1315 static const struct GNUNET_REST_RequestHandler handlers[] =
1316 { { MHD_HTTP_METHOD_GET,
1317 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1318 &list_attribute_cont },
1319 { MHD_HTTP_METHOD_POST,
1320 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1321 &add_attribute_cont },
1322 { MHD_HTTP_METHOD_DELETE,
1323 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1324 &delete_attribute_cont },
1325 { MHD_HTTP_METHOD_GET,
1326 GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1327 &list_attestation_cont },
1328 { MHD_HTTP_METHOD_POST,
1329 GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1330 &add_attestation_cont },
1331 { MHD_HTTP_METHOD_DELETE,
1332 GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1333 &delete_attestation_cont },
1334 { MHD_HTTP_METHOD_GET,
1335 GNUNET_REST_API_NS_IDENTITY_TICKETS,
1336 &list_tickets_cont },
1337 { MHD_HTTP_METHOD_POST,
1338 GNUNET_REST_API_NS_IDENTITY_REVOKE,
1339 &revoke_ticket_cont },
1340 { MHD_HTTP_METHOD_POST,
1341 GNUNET_REST_API_NS_IDENTITY_CONSUME,
1342 &consume_ticket_cont },
1343 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, &options_cont },
1344 GNUNET_REST_HANDLER_END };
1347 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1349 handle->response_code = err.error_code;
1350 GNUNET_SCHEDULER_add_now (&do_error, handle);
1356 * If listing is enabled, prints information about the egos.
1358 * This function is initially called for all egos and then again
1359 * whenever a ego's identifier changes or if it is deleted. At the
1360 * end of the initial pass over all egos, the function is once called
1361 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1362 * be invoked in the future or that there was an error.
1364 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1365 * this function is only called ONCE, and 'NULL' being passed in
1366 * 'ego' does indicate an error (i.e. name is taken or no default
1367 * value is known). If 'ego' is non-NULL and if '*ctx'
1368 * is set in those callbacks, the value WILL be passed to a subsequent
1369 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1370 * that one was not NULL).
1372 * When an identity is renamed, this function is called with the
1373 * (known) ego but the NEW identifier.
1375 * When an identity is deleted, this function is called with the
1376 * (known) ego and "NULL" for the 'identifier'. In this case,
1377 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1380 * @param cls closure
1381 * @param ego ego handle
1382 * @param ctx context for application to store data for this ego
1383 * (during the lifetime of this process, initially NULL)
1384 * @param identifier identifier assigned by the user for this ego,
1385 * NULL if the user just deleted the ego and it
1386 * must thus no longer be used
1389 list_ego (void *cls,
1390 struct GNUNET_IDENTITY_Ego *ego,
1392 const char *identifier)
1394 struct RequestHandle *handle = cls;
1395 struct EgoEntry *ego_entry;
1396 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1398 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1400 handle->state = ID_REST_STATE_POST_INIT;
1404 if (ID_REST_STATE_INIT == handle->state)
1406 ego_entry = GNUNET_new (struct EgoEntry);
1407 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1408 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1409 ego_entry->ego = ego;
1410 ego_entry->identifier = GNUNET_strdup (identifier);
1411 GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
1419 rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1420 GNUNET_REST_ResultProcessor proc,
1423 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1425 handle->response_code = 0;
1426 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1427 handle->proc_cls = proc_cls;
1428 handle->proc = proc;
1429 handle->state = ID_REST_STATE_INIT;
1430 handle->rest_handle = rest_handle;
1432 handle->url = GNUNET_strdup (rest_handle->url);
1433 if (handle->url[strlen (handle->url) - 1] == '/')
1434 handle->url[strlen (handle->url) - 1] = '\0';
1435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1436 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
1437 handle->timeout_task =
1438 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
1439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1444 * Entry point for the plugin.
1446 * @param cls Config info
1447 * @return NULL on error, otherwise the plugin context
1450 libgnunet_plugin_rest_reclaim_init (void *cls)
1452 static struct Plugin plugin;
1453 struct GNUNET_REST_Plugin *api;
1456 if (NULL != plugin.cfg)
1457 return NULL; /* can only initialize once! */
1458 memset (&plugin, 0, sizeof(struct Plugin));
1460 api = GNUNET_new (struct GNUNET_REST_Plugin);
1462 api->name = GNUNET_REST_API_NS_RECLAIM;
1463 api->process_request = &rest_identity_process_request;
1464 GNUNET_asprintf (&allow_methods,
1465 "%s, %s, %s, %s, %s",
1466 MHD_HTTP_METHOD_GET,
1467 MHD_HTTP_METHOD_POST,
1468 MHD_HTTP_METHOD_PUT,
1469 MHD_HTTP_METHOD_DELETE,
1470 MHD_HTTP_METHOD_OPTIONS);
1472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1473 _ ("Identity Provider REST API initialized\n"));
1479 * Exit point from the plugin.
1481 * @param cls the plugin context (as returned by "init")
1482 * @return always NULL
1485 libgnunet_plugin_rest_reclaim_done (void *cls)
1487 struct GNUNET_REST_Plugin *api = cls;
1488 struct Plugin *plugin = api->cls;
1492 GNUNET_free_non_null (allow_methods);
1494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1495 "Identity Provider REST plugin is finished\n");
1500 /* end of plugin_rest_reclaim.c */