use NULL value in load_path_suffix to NOT load any files
[oweals/gnunet.git] / src / reclaim / plugin_rest_reclaim.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2012-2015 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18    SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @author Martin Schanzenbach
22  * @author Philippe Buschmann
23  * @file reclaim/plugin_rest_reclaim.c
24  * @brief GNUnet reclaim REST plugin
25  *
26  */
27 #include "platform.h"
28 #include "microhttpd.h"
29 #include <inttypes.h>
30 #include <jansson.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"
40 /**
41  * REST root namespace
42  */
43 #define GNUNET_REST_API_NS_RECLAIM "/reclaim"
44
45 /**
46  * Attribute namespace
47  */
48 #define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/reclaim/attributes"
49
50 /**
51    * Attestation namespace
52    */
53 #define GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE "/reclaim/attestation"
54
55 /**
56  * Ticket namespace
57  */
58 #define GNUNET_REST_API_NS_IDENTITY_TICKETS "/reclaim/tickets"
59
60 /**
61  * Revoke namespace
62  */
63 #define GNUNET_REST_API_NS_IDENTITY_REVOKE "/reclaim/revoke"
64
65 /**
66  * Revoke namespace
67  */
68 #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/reclaim/consume"
69
70 /**
71  * State while collecting all egos
72  */
73 #define ID_REST_STATE_INIT 0
74
75 /**
76  * Done collecting egos
77  */
78 #define ID_REST_STATE_POST_INIT 1
79
80 /**
81  * The configuration handle
82  */
83 const struct GNUNET_CONFIGURATION_Handle *cfg;
84
85 /**
86  * HTTP methods allows for this plugin
87  */
88 static char *allow_methods;
89
90 /**
91  * @brief struct returned by the initialization function of the plugin
92  */
93 struct Plugin
94 {
95   const struct GNUNET_CONFIGURATION_Handle *cfg;
96 };
97
98 /**
99  * The ego list
100  */
101 struct EgoEntry
102 {
103   /**
104    * DLL
105    */
106   struct EgoEntry *next;
107
108   /**
109    * DLL
110    */
111   struct EgoEntry *prev;
112
113   /**
114    * Ego Identifier
115    */
116   char *identifier;
117
118   /**
119    * Public key string
120    */
121   char *keystring;
122
123   /**
124    * The Ego
125    */
126   struct GNUNET_IDENTITY_Ego *ego;
127 };
128
129
130 struct RequestHandle
131 {
132   /**
133    * Ego list
134    */
135   struct EgoEntry *ego_head;
136
137   /**
138    * Ego list
139    */
140   struct EgoEntry *ego_tail;
141
142   /**
143    * Selected ego
144    */
145   struct EgoEntry *ego_entry;
146
147   /**
148    * Pointer to ego private key
149    */
150   struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
151
152   /**
153    * The processing state
154    */
155   int state;
156
157   /**
158    * Handle to Identity service.
159    */
160   struct GNUNET_IDENTITY_Handle *identity_handle;
161
162   /**
163    * Rest connection
164    */
165   struct GNUNET_REST_RequestHandle *rest_handle;
166
167   /**
168    * Attribute claim list
169    */
170   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list;
171
172   /**
173    * IDENTITY Operation
174    */
175   struct GNUNET_IDENTITY_Operation *op;
176
177   /**
178    * Identity Provider
179    */
180   struct GNUNET_RECLAIM_Handle *idp;
181
182   /**
183    * Idp Operation
184    */
185   struct GNUNET_RECLAIM_Operation *idp_op;
186
187   /**
188    * Attribute iterator
189    */
190   struct GNUNET_RECLAIM_AttributeIterator *attr_it;
191
192   /**
193    * Ticket iterator
194    */
195   struct GNUNET_RECLAIM_TicketIterator *ticket_it;
196
197   /**
198    * A ticket
199    */
200   struct GNUNET_RECLAIM_Ticket ticket;
201
202   /**
203    * Desired timeout for the lookup (default is no timeout).
204    */
205   struct GNUNET_TIME_Relative timeout;
206
207   /**
208    * ID of a task associated with the resolution process.
209    */
210   struct GNUNET_SCHEDULER_Task *timeout_task;
211
212   /**
213    * The plugin result processor
214    */
215   GNUNET_REST_ResultProcessor proc;
216
217   /**
218    * The closure of the result processor
219    */
220   void *proc_cls;
221
222   /**
223    * The url
224    */
225   char *url;
226
227   /**
228    * Error response message
229    */
230   char *emsg;
231
232   /**
233    * Reponse code
234    */
235   int response_code;
236
237   /**
238    * Response object
239    */
240   json_t *resp_object;
241 };
242
243 /**
244  * Cleanup lookup handle
245  * @param handle Handle to clean up
246  */
247 static void
248 cleanup_handle (struct RequestHandle *handle)
249 {
250   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry;
251   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp;
252   struct EgoEntry *ego_entry;
253   struct EgoEntry *ego_tmp;
254
255   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
256   if (NULL != handle->resp_object)
257     json_decref (handle->resp_object);
258   if (NULL != handle->timeout_task)
259     GNUNET_SCHEDULER_cancel (handle->timeout_task);
260   if (NULL != handle->identity_handle)
261     GNUNET_IDENTITY_disconnect (handle->identity_handle);
262   if (NULL != handle->attr_it)
263     GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
264   if (NULL != handle->ticket_it)
265     GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
266   if (NULL != handle->idp)
267     GNUNET_RECLAIM_disconnect (handle->idp);
268   if (NULL != handle->url)
269     GNUNET_free (handle->url);
270   if (NULL != handle->emsg)
271     GNUNET_free (handle->emsg);
272   if (NULL != handle->attr_list)
273   {
274     for (claim_entry = handle->attr_list->list_head; NULL != claim_entry;)
275     {
276       claim_tmp = claim_entry;
277       claim_entry = claim_entry->next;
278       GNUNET_free (claim_tmp->claim);
279       GNUNET_free (claim_tmp->attest);
280       GNUNET_free (claim_tmp->reference);
281       GNUNET_free (claim_tmp);
282     }
283     GNUNET_free (handle->attr_list);
284   }
285   for (ego_entry = handle->ego_head; NULL != ego_entry;)
286   {
287     ego_tmp = ego_entry;
288     ego_entry = ego_entry->next;
289     GNUNET_free (ego_tmp->identifier);
290     GNUNET_free (ego_tmp->keystring);
291     GNUNET_free (ego_tmp);
292   }
293   GNUNET_free (handle);
294 }
295
296
297 static void
298 cleanup_handle_delayed (void *cls)
299 {
300   cleanup_handle (cls);
301 }
302
303
304 /**
305  * Task run on error, sends error message.  Cleans up everything.
306  *
307  * @param cls the `struct RequestHandle`
308  */
309 static void
310 do_error (void *cls)
311 {
312   struct RequestHandle *handle = cls;
313   struct MHD_Response *resp;
314   char *json_error;
315
316   GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", handle->emsg);
317   if (0 == handle->response_code)
318   {
319     handle->response_code = MHD_HTTP_BAD_REQUEST;
320   }
321   resp = GNUNET_REST_create_response (json_error);
322   MHD_add_response_header (resp, "Content-Type", "application/json");
323   handle->proc (handle->proc_cls, resp, handle->response_code);
324   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
325   GNUNET_free (json_error);
326 }
327
328
329 /**
330  * Task run on timeout, sends error message.  Cleans up everything.
331  *
332  * @param cls the `struct RequestHandle`
333  */
334 static void
335 do_timeout (void *cls)
336 {
337   struct RequestHandle *handle = cls;
338
339   handle->timeout_task = NULL;
340   do_error (handle);
341 }
342
343
344 static void
345 collect_error_cb (void *cls)
346 {
347   struct RequestHandle *handle = cls;
348
349   do_error (handle);
350 }
351
352
353 static void
354 finished_cont (void *cls, int32_t success, const char *emsg)
355 {
356   struct RequestHandle *handle = cls;
357   struct MHD_Response *resp;
358
359   resp = GNUNET_REST_create_response (emsg);
360   if (GNUNET_OK != success)
361   {
362     GNUNET_SCHEDULER_add_now (&do_error, handle);
363     return;
364   }
365   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
366   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
367 }
368
369 static void
370 delete_finished_cb (void *cls, int32_t success, const char *emsg)
371 {
372   struct RequestHandle *handle = cls;
373   struct MHD_Response *resp;
374
375   resp = GNUNET_REST_create_response (emsg);
376   if (GNUNET_OK != success)
377   {
378     GNUNET_SCHEDULER_add_now (&do_error, handle);
379     return;
380   }
381   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
382   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
383 }
384
385 /**
386  * Return attributes for identity
387  *
388  * @param cls the request handle
389  */
390 static void
391 return_response (void *cls)
392 {
393   char *result_str;
394   struct RequestHandle *handle = cls;
395   struct MHD_Response *resp;
396
397   result_str = json_dumps (handle->resp_object, 0);
398   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
399   resp = GNUNET_REST_create_response (result_str);
400   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
401   GNUNET_free (result_str);
402   cleanup_handle (handle);
403 }
404
405
406 static void
407 collect_finished_cb (void *cls)
408 {
409   struct RequestHandle *handle = cls;
410
411   // Done
412   handle->attr_it = NULL;
413   handle->ticket_it = NULL;
414   GNUNET_SCHEDULER_add_now (&return_response, handle);
415 }
416
417
418 /**
419  * Collect all attributes for an ego
420  *
421  */
422 static void
423 ticket_collect (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
424 {
425   json_t *json_resource;
426   struct RequestHandle *handle = cls;
427   json_t *value;
428   char *tmp;
429
430   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
431   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(uint64_t));
432   json_resource = json_object ();
433   GNUNET_free (tmp);
434   json_array_append (handle->resp_object, json_resource);
435
436   tmp =
437     GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
438                                          sizeof(struct
439                                                 GNUNET_CRYPTO_EcdsaPublicKey));
440   value = json_string (tmp);
441   json_object_set_new (json_resource, "issuer", value);
442   GNUNET_free (tmp);
443   tmp =
444     GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
445                                          sizeof(struct
446                                                 GNUNET_CRYPTO_EcdsaPublicKey));
447   value = json_string (tmp);
448   json_object_set_new (json_resource, "audience", value);
449   GNUNET_free (tmp);
450   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(uint64_t));
451   value = json_string (tmp);
452   json_object_set_new (json_resource, "rnd", value);
453   GNUNET_free (tmp);
454   GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it);
455 }
456
457
458 static void
459 add_attestation_ref_cont (struct GNUNET_REST_RequestHandle *con_handle,
460                           const char *url,
461                           void *cls)
462 {
463   struct RequestHandle *handle = cls;
464   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
465   const char *identity;
466   struct EgoEntry *ego_entry;
467   struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attribute;
468   struct GNUNET_TIME_Relative exp;
469   char term_data[handle->rest_handle->data_size + 1];
470   json_t *data_json;
471   json_error_t err;
472   struct GNUNET_JSON_Specification attrspec[] =
473   { GNUNET_RECLAIM_JSON_spec_claim_attest_ref (&attribute),
474     GNUNET_JSON_spec_end () };
475   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
476               "Adding an attestation reference for %s.\n",
477               handle->url);
478   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + strlen (
479         "reference/") + 1 >= strlen (
480         handle->url))
481   {
482     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
483     GNUNET_SCHEDULER_add_now (&do_error, handle);
484     return;
485   }
486   identity = handle->url + strlen (
487     GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + strlen ("reference/")
488              + 1;
489   for (ego_entry = handle->ego_head; NULL != ego_entry;
490        ego_entry = ego_entry->next)
491     if (0 == strcmp (identity, ego_entry->identifier))
492       break;
493   if (NULL == ego_entry)
494   {
495     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
496     return;
497   }
498   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
499   if (0 >= handle->rest_handle->data_size)
500   {
501     GNUNET_SCHEDULER_add_now (&do_error, handle);
502     return;
503   }
504
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)
514   {
515     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
516                 "Unable to parse attestation reference from %s\n",
517                 term_data);
518     GNUNET_SCHEDULER_add_now (&do_error, handle);
519     return;
520   }
521   /**
522    * New ID for attribute
523    */
524   if (0 == attribute->id)
525     attribute->id = attribute->id_attest;
526   handle->idp = GNUNET_RECLAIM_connect (cfg);
527   exp = GNUNET_TIME_UNIT_HOURS;
528   handle->idp_op = GNUNET_RECLAIM_attestation_reference_store (handle->idp,
529                                                                identity_priv,
530                                                                attribute,
531                                                                &exp,
532                                                                &finished_cont,
533                                                                handle);
534   GNUNET_JSON_parse_free (attrspec);
535 }
536
537 static void
538 parse_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
539                         const char *url,
540                         void *cls)
541 {
542   struct RequestHandle *handle = cls;
543
544   char term_data[handle->rest_handle->data_size + 1];
545   json_t *data_json;
546   json_error_t err;
547   int unpack_state;
548   struct MHD_Response *resp;
549   char *val_str = NULL;
550   const char *type_str = NULL;
551   term_data[handle->rest_handle->data_size] = '\0';
552   GNUNET_memcpy (term_data,
553                  handle->rest_handle->data,
554                  handle->rest_handle->data_size);
555   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
556   GNUNET_assert (NULL != data_json);
557   if (! json_is_object (data_json))
558   {
559     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
560                 "Error json is not array nor object!\n");
561     GNUNET_SCHEDULER_add_now (&do_error, handle);
562     return;
563   }
564   unpack_state = json_unpack (data_json,
565                               "{s:s, s:s!}",
566                               "value",
567                               &val_str,
568                               "type",
569                               &type_str);
570   if ((0 != unpack_state) || (NULL == val_str) || (NULL == type_str))
571   {
572     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
573                 "Error json object has a wrong format!\n");
574     GNUNET_SCHEDULER_add_now (&do_error, handle);
575     return;
576   }
577   if (0 == strcmp (type_str, "JWT"))
578   {
579   // The value is a JWT
580   char *decoded_jwt;
581   char delim[] = ".";
582   char *jwt_body = strtok (val_str, delim);
583   jwt_body = strtok (NULL, delim);
584   GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body),
585                                 (void **) &decoded_jwt);
586   resp = GNUNET_REST_create_response (decoded_jwt);
587   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
588   GNUNET_free (decoded_jwt);
589   }
590   else
591   {
592     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
593                 "Error requested parsing type not supported!\n");
594     GNUNET_SCHEDULER_add_now (&do_error, handle);
595     return;
596   }
597   cleanup_handle (handle);
598   json_decref (data_json);
599 }
600
601 static void
602 add_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
603                       const char *url,
604                       void *cls)
605 {
606   struct RequestHandle *handle = cls;
607   /* Check for substring "reference" */
608   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) < strlen (
609         handle->url))
610   {
611     if ( strncmp ("reference/", (handle->url + strlen (
612                                    GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE)
613                                  + 1), strlen (
614                     "reference/")) == 0)
615     {
616       add_attestation_ref_cont (con_handle,url,cls);
617       return;
618     }
619   }
620   /* Check for substring "parse" */
621   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) < strlen (
622       handle->url))
623       {
624         if ( strncmp ("parse", (handle->url + strlen (
625                           GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE)
626                         + 1), strlen (
627             "parse")) == 0)
628         {
629           parse_attestation_cont (con_handle,url,cls);
630           return;
631         }
632       }
633   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
634   const char *identity;
635   struct EgoEntry *ego_entry;
636   struct GNUNET_RECLAIM_ATTESTATION_Claim *attribute;
637   struct GNUNET_TIME_Relative exp;
638   char term_data[handle->rest_handle->data_size + 1];
639   json_t *data_json;
640   json_error_t err;
641   struct GNUNET_JSON_Specification attrspec[] =
642   { GNUNET_RECLAIM_JSON_spec_claim_attest (&attribute),
643     GNUNET_JSON_spec_end () };
644
645   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
646               "Adding an attestation for %s.\n",
647               handle->url);
648   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) >= strlen (
649         handle->url))
650   {
651     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
652     GNUNET_SCHEDULER_add_now (&do_error, handle);
653     return;
654   }
655   identity = handle->url + strlen (
656     GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + 1;
657
658   for (ego_entry = handle->ego_head; NULL != ego_entry;
659        ego_entry = ego_entry->next)
660     if (0 == strcmp (identity, ego_entry->identifier))
661       break;
662
663   if (NULL == ego_entry)
664   {
665     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
666     return;
667   }
668   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
669
670   if (0 >= handle->rest_handle->data_size)
671   {
672     GNUNET_SCHEDULER_add_now (&do_error, handle);
673     return;
674   }
675
676   term_data[handle->rest_handle->data_size] = '\0';
677   GNUNET_memcpy (term_data,
678                  handle->rest_handle->data,
679                  handle->rest_handle->data_size);
680   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
681   GNUNET_assert (GNUNET_OK ==
682                  GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
683   json_decref (data_json);
684   if (NULL == attribute)
685   {
686     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
687                 "Unable to parse attestation from %s\n",
688                 term_data);
689     GNUNET_SCHEDULER_add_now (&do_error, handle);
690     return;
691   }
692   /**
693    * New ID for attribute
694    */
695   if (0 == attribute->id)
696     attribute->id =
697       GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
698   handle->idp = GNUNET_RECLAIM_connect (cfg);
699   exp = GNUNET_TIME_UNIT_HOURS;
700   handle->idp_op = GNUNET_RECLAIM_attestation_store (handle->idp,
701                                                      identity_priv,
702                                                      attribute,
703                                                      &exp,
704                                                      &finished_cont,
705                                                      handle);
706   GNUNET_JSON_parse_free (attrspec);
707 }
708
709 /**
710  * Collect all references for an ego
711  *
712  */
713 static void
714 ref_collect (void *cls,
715              const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
716              const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
717              const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest,
718              const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference)
719 {
720   struct RequestHandle *handle = cls;
721   json_t *attr_obj;
722   char *id_str;
723   char *id_attest_str;
724
725   if (NULL == reference)
726   {
727     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
728     return;
729   }
730
731   if ((NULL == reference->name) || (NULL == reference->reference_value))
732   {
733     return;
734   }
735
736   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding reference: %s\n",
737               reference->name);
738   attr_obj = json_object ();
739   json_object_set_new (attr_obj, "name", json_string (reference->name));
740   json_object_set_new (attr_obj, "ref_value", json_string (
741                          reference->reference_value));
742   id_str = GNUNET_STRINGS_data_to_string_alloc (&reference->id,
743                                                 sizeof(uint64_t));
744   id_attest_str = GNUNET_STRINGS_data_to_string_alloc (&reference->id_attest,
745                                                        sizeof(uint64_t));
746   json_object_set_new (attr_obj, "id", json_string (id_str));
747   json_object_set_new (attr_obj, "ref_id", json_string (id_attest_str));
748   json_array_append (handle->resp_object, attr_obj);
749   json_decref (attr_obj);
750 }
751
752 /**
753  * Lists references for identity request
754  *
755  * @param con_handle the connection handle
756  * @param url the url
757  * @param cls the RequestHandle
758  */
759 static void
760 list_reference_cont (struct GNUNET_REST_RequestHandle *con_handle,
761                      const char *url,
762                      void *cls)
763 {
764   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
765   struct RequestHandle *handle = cls;
766   struct EgoEntry *ego_entry;
767   char *identity;
768
769   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
770               "Getting references for %s.\n",
771               handle->url);
772   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + strlen (
773         "reference/") + 1 >= strlen (
774         handle->url))
775   {
776     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
777     GNUNET_SCHEDULER_add_now (&do_error, handle);
778     return;
779   }
780   identity = handle->url + strlen (
781     GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + strlen ("reference/")
782              + 1;
783   for (ego_entry = handle->ego_head; NULL != ego_entry;
784        ego_entry = ego_entry->next)
785     if (0 == strcmp (identity, ego_entry->identifier))
786       break;
787   handle->resp_object = json_array ();
788
789   if (NULL == ego_entry)
790   {
791     // Done
792     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
793     GNUNET_SCHEDULER_add_now (&return_response, handle);
794     return;
795   }
796   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
797   handle->idp = GNUNET_RECLAIM_connect (cfg);
798   handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
799                                                          priv_key,
800                                                          &collect_error_cb,
801                                                          handle,
802                                                          &ref_collect,
803                                                          handle,
804                                                          &collect_finished_cb,
805                                                          handle);
806 }
807
808 /**
809  * Collect all attestations for an ego
810  *
811  */
812 static void
813 attest_collect (void *cls,
814                 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
815                 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
816                 const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest,
817                 const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference)
818 {
819   struct RequestHandle *handle = cls;
820   json_t *attr_obj;
821   const char *type;
822   char *tmp_value;
823   char *id_str;
824
825
826   if (NULL != reference)
827   {
828     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
829                 "Attestation Collection with Reference\n");
830     return;
831   }
832   if (NULL == attest)
833   {
834     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
835                 "Attestation Collection with empty Attestation\n");
836     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
837     return;
838   }
839
840   if ((NULL == attest->name) || (NULL == attest->data))
841   {
842     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
843                 "Attestation Collection with empty Name/Value\n");
844     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
845     return;
846   }
847
848   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attestation: %s\n",
849               attest->name);
850
851   tmp_value = GNUNET_RECLAIM_ATTESTATION_value_to_string (attest->type,
852                                                           attest->data,
853                                                           attest->data_size);
854   attr_obj = json_object ();
855   json_object_set_new (attr_obj, "value", json_string (tmp_value));
856   json_object_set_new (attr_obj, "name", json_string (attest->name));
857   type = GNUNET_RECLAIM_ATTESTATION_number_to_typename (attest->type);
858   json_object_set_new (attr_obj, "type", json_string (type));
859   id_str = GNUNET_STRINGS_data_to_string_alloc (&attest->id, sizeof(uint64_t));
860   json_object_set_new (attr_obj, "id", json_string (id_str));
861   json_array_append (handle->resp_object, attr_obj);
862   json_decref (attr_obj);
863   GNUNET_free (tmp_value);
864   GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
865 }
866
867
868 /**
869  * Lists attestation for identity request
870  *
871  * @param con_handle the connection handle
872  * @param url the url
873  * @param cls the RequestHandle
874  */
875 static void
876 list_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
877                        const char *url,
878                        void *cls)
879 {
880   struct RequestHandle *handle = cls;
881   /* Check for substring "reference" */
882   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) < strlen (
883         handle->url))
884   {
885     if ( strncmp ("reference/", (handle->url + strlen (
886                                    GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE)
887                                  + 1), strlen (
888                     "reference/")) == 0)
889     {
890       list_reference_cont (con_handle,url,cls);
891       return;
892     }
893   }
894   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
895   struct EgoEntry *ego_entry;
896   char *identity;
897
898   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
899               "Getting attestations for %s.\n",
900               handle->url);
901   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) >= strlen (
902         handle->url))
903   {
904     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
905     GNUNET_SCHEDULER_add_now (&do_error, handle);
906     return;
907   }
908   identity = handle->url + strlen (
909     GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + 1;
910
911   for (ego_entry = handle->ego_head; NULL != ego_entry;
912        ego_entry = ego_entry->next)
913     if (0 == strcmp (identity, ego_entry->identifier))
914       break;
915   handle->resp_object = json_array ();
916
917
918   if (NULL == ego_entry)
919   {
920     // Done
921     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
922     GNUNET_SCHEDULER_add_now (&return_response, handle);
923     return;
924   }
925   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
926   handle->idp = GNUNET_RECLAIM_connect (cfg);
927   handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
928                                                          priv_key,
929                                                          &collect_error_cb,
930                                                          handle,
931                                                          &attest_collect,
932                                                          handle,
933                                                          &collect_finished_cb,
934                                                          handle);
935 }
936
937 /**
938  * Deletes reference from an identity
939  *
940  * @param con_handle the connection handle
941  * @param url the url
942  * @param cls the RequestHandle
943  */
944 static void
945 delete_attestation_ref_cont (struct GNUNET_REST_RequestHandle *con_handle,
946                              const char *url,
947                              void *cls)
948 {
949   struct RequestHandle *handle = cls;
950   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
951   struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr;
952   struct EgoEntry *ego_entry;
953   char *identity;
954   char *identity_id_str;
955   char *id;
956   char term_data[handle->rest_handle->data_size + 1];
957   json_t *data_json;
958   json_error_t err;
959
960   struct GNUNET_JSON_Specification attrspec[] =
961   { GNUNET_RECLAIM_JSON_spec_claim_attest_ref (&attr),
962     GNUNET_JSON_spec_end () };
963   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
964               "Deleting attestation reference.\n");
965   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + strlen (
966         "reference/") + 1 >= strlen (
967         handle->url))
968   {
969     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
970     GNUNET_SCHEDULER_add_now (&do_error, handle);
971     return;
972   }
973   identity_id_str = strdup (handle->url + strlen (
974                               GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE)
975                             + strlen ("reference/")
976                             + 1);
977   identity = strtok (identity_id_str, "/");
978   id = strtok (NULL, "/");
979
980   if ((NULL == identity) || (NULL == id))
981   {
982     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
983     GNUNET_SCHEDULER_add_now (&do_error, handle);
984     return;
985   }
986   for (ego_entry = handle->ego_head; NULL != ego_entry;
987        ego_entry = ego_entry->next)
988     if (0 == strcmp (identity, ego_entry->identifier))
989       break;
990   handle->resp_object = json_array ();
991   if (NULL == ego_entry)
992   {
993     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
994     GNUNET_SCHEDULER_add_now (&return_response, handle);
995     return;
996   }
997   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
998   if (0 >= handle->rest_handle->data_size)
999   {
1000     GNUNET_SCHEDULER_add_now (&do_error, handle);
1001     return;
1002   }
1003
1004   term_data[handle->rest_handle->data_size] = '\0';
1005   GNUNET_memcpy (term_data,
1006                  handle->rest_handle->data,
1007                  handle->rest_handle->data_size);
1008   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1009   GNUNET_assert (GNUNET_OK ==
1010                  GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
1011   json_decref (data_json);
1012   if (NULL == attr)
1013   {
1014     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1015                 "Unable to parse attestation reference from %s\n",
1016                 term_data);
1017     GNUNET_SCHEDULER_add_now (&do_error, handle);
1018     return;
1019   }
1020   GNUNET_STRINGS_string_to_data (id, strlen (id), &attr->id, sizeof(uint64_t));
1021
1022   handle->idp = GNUNET_RECLAIM_connect (cfg);
1023   handle->idp_op = GNUNET_RECLAIM_attestation_reference_delete (handle->idp,
1024                                                                 priv_key,
1025                                                                 attr,
1026                                                                 &
1027                                                                 delete_finished_cb,
1028                                                                 handle);
1029   GNUNET_JSON_parse_free (attrspec);
1030 }
1031
1032
1033 /**
1034  * Deletes attestation from an identity
1035  *
1036  * @param con_handle the connection handle
1037  * @param url the url
1038  * @param cls the RequestHandle
1039  */
1040 static void
1041 delete_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
1042                          const char *url,
1043                          void *cls)
1044 {
1045   struct RequestHandle *handle = cls;
1046   /* Check for substring "reference" */
1047   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) < strlen (
1048         handle->url))
1049   {
1050     if ( strncmp ("reference", (handle->url + strlen (
1051                                   GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE)
1052                                 + 1), strlen (
1053                     "reference")) == 0)
1054     {
1055       delete_attestation_ref_cont (con_handle,url,cls);
1056       return;
1057     }
1058   }
1059   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1060   struct GNUNET_RECLAIM_ATTESTATION_Claim attr;
1061   struct EgoEntry *ego_entry;
1062   char *identity_id_str;
1063   char *identity;
1064   char *id;
1065
1066   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attestation.\n");
1067   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) >= strlen (
1068         handle->url))
1069   {
1070     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1071     GNUNET_SCHEDULER_add_now (&do_error, handle);
1072     return;
1073   }
1074   identity_id_str =
1075     strdup (handle->url + strlen (
1076               GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + 1);
1077   identity = strtok (identity_id_str, "/");
1078   id = strtok (NULL, "/");
1079   if ((NULL == identity) || (NULL == id))
1080   {
1081     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
1082     GNUNET_free (identity_id_str);
1083     GNUNET_SCHEDULER_add_now (&do_error, handle);
1084     return;
1085   }
1086
1087   for (ego_entry = handle->ego_head; NULL != ego_entry;
1088        ego_entry = ego_entry->next)
1089     if (0 == strcmp (identity, ego_entry->identifier))
1090       break;
1091   handle->resp_object = json_array ();
1092   if (NULL == ego_entry)
1093   {
1094     // Done
1095     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1096     GNUNET_free (identity_id_str);
1097     GNUNET_SCHEDULER_add_now (&return_response, handle);
1098     return;
1099   }
1100   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1101   handle->idp = GNUNET_RECLAIM_connect (cfg);
1102   memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_ATTESTATION_Claim));
1103   GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(uint64_t));
1104   attr.name = "";
1105   handle->idp_op = GNUNET_RECLAIM_attestation_delete (handle->idp,
1106                                                       priv_key,
1107                                                       &attr,
1108                                                       &delete_finished_cb,
1109                                                       handle);
1110   GNUNET_free (identity_id_str);
1111 }
1112
1113 /**
1114  * List tickets for identity request
1115  *
1116  * @param con_handle the connection handle
1117  * @param url the url
1118  * @param cls the RequestHandle
1119  */
1120 static void
1121 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
1122                    const char *url,
1123                    void *cls)
1124 {
1125   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1126   struct RequestHandle *handle = cls;
1127   struct EgoEntry *ego_entry;
1128   char *identity;
1129
1130   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1131               "Getting tickets for %s.\n",
1132               handle->url);
1133   if (strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= strlen (handle->url))
1134   {
1135     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1136     GNUNET_SCHEDULER_add_now (&do_error, handle);
1137     return;
1138   }
1139   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
1140
1141   for (ego_entry = handle->ego_head; NULL != ego_entry;
1142        ego_entry = ego_entry->next)
1143     if (0 == strcmp (identity, ego_entry->identifier))
1144       break;
1145   handle->resp_object = json_array ();
1146
1147   if (NULL == ego_entry)
1148   {
1149     // Done
1150     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1151     GNUNET_SCHEDULER_add_now (&return_response, handle);
1152     return;
1153   }
1154   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1155   handle->idp = GNUNET_RECLAIM_connect (cfg);
1156   handle->ticket_it =
1157     GNUNET_RECLAIM_ticket_iteration_start (handle->idp,
1158                                            priv_key,
1159                                            &collect_error_cb,
1160                                            handle,
1161                                            &ticket_collect,
1162                                            handle,
1163                                            &collect_finished_cb,
1164                                            handle);
1165 }
1166
1167
1168 static void
1169 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1170                     const char *url,
1171                     void *cls)
1172 {
1173   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1174   const char *identity;
1175   struct RequestHandle *handle = cls;
1176   struct EgoEntry *ego_entry;
1177   struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute;
1178   struct GNUNET_TIME_Relative exp;
1179   char term_data[handle->rest_handle->data_size + 1];
1180   json_t *data_json;
1181   json_error_t err;
1182   struct GNUNET_JSON_Specification attrspec[] =
1183   { GNUNET_RECLAIM_JSON_spec_claim (&attribute), GNUNET_JSON_spec_end () };
1184
1185   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1186               "Adding an attribute for %s.\n",
1187               handle->url);
1188   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1189   {
1190     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1191     GNUNET_SCHEDULER_add_now (&do_error, handle);
1192     return;
1193   }
1194   identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
1195
1196   for (ego_entry = handle->ego_head; NULL != ego_entry;
1197        ego_entry = ego_entry->next)
1198     if (0 == strcmp (identity, ego_entry->identifier))
1199       break;
1200
1201   if (NULL == ego_entry)
1202   {
1203     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
1204     return;
1205   }
1206   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1207
1208   if (0 >= handle->rest_handle->data_size)
1209   {
1210     GNUNET_SCHEDULER_add_now (&do_error, handle);
1211     return;
1212   }
1213
1214   term_data[handle->rest_handle->data_size] = '\0';
1215   GNUNET_memcpy (term_data,
1216                  handle->rest_handle->data,
1217                  handle->rest_handle->data_size);
1218   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1219   GNUNET_assert (GNUNET_OK ==
1220                  GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
1221   json_decref (data_json);
1222   if (NULL == attribute)
1223   {
1224     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1225                 "Unable to parse attribute from %s\n",
1226                 term_data);
1227     GNUNET_SCHEDULER_add_now (&do_error, handle);
1228     return;
1229   }
1230   /**
1231    * New ID for attribute
1232    */
1233   if (0 == attribute->id)
1234     attribute->id =
1235       GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
1236   handle->idp = GNUNET_RECLAIM_connect (cfg);
1237   exp = GNUNET_TIME_UNIT_HOURS;
1238   handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
1239                                                    identity_priv,
1240                                                    attribute,
1241                                                    &exp,
1242                                                    &finished_cont,
1243                                                    handle);
1244   GNUNET_JSON_parse_free (attrspec);
1245 }
1246
1247 /**
1248  * Parse a JWT and return the respective claim value as Attribute
1249  *
1250  * @param attest the jwt attestation
1251  * @param claim the name of the claim in the JWT
1252  *
1253  * @return a GNUNET_RECLAIM_ATTRIBUTE_Claim, containing the new value
1254  */
1255 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *
1256 parse_jwt (const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest,
1257            const char *claim)
1258 {
1259   char *jwt_string;
1260   struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr;
1261   char delim[] = ".";
1262   const char *type_str = NULL;
1263   const char *val_str = NULL;
1264   char *data;
1265   size_t data_size;
1266   uint32_t type;
1267   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing JWT attributes.\n");
1268   char *decoded_jwt;
1269   json_t *json_val;
1270   json_error_t *json_err = NULL;
1271
1272   jwt_string = GNUNET_RECLAIM_ATTESTATION_value_to_string (attest->type,
1273                                                            attest->data,
1274                                                            attest->data_size);
1275   char *jwt_body = strtok (jwt_string, delim);
1276   jwt_body = strtok (NULL, delim);
1277   GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body),
1278                                 (void **) &decoded_jwt);
1279   json_val = json_loads (decoded_jwt, JSON_DECODE_ANY, json_err);
1280   const char *key;
1281   json_t *value;
1282   json_object_foreach (json_val, key, value) {
1283     if (0 == strcasecmp (key,claim))
1284     {
1285       val_str = json_dumps (value, JSON_ENCODE_ANY);
1286     }
1287   }
1288   type_str = "String";
1289   type = GNUNET_RECLAIM_ATTRIBUTE_typename_to_number (type_str);
1290   if (GNUNET_SYSERR ==(GNUNET_RECLAIM_ATTRIBUTE_string_to_value (type,val_str,
1291                                                                  (void **) &data,
1292                                                                  &data_size)))
1293   {
1294     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1295                 "Attribute value from JWT Parser invalid!\n");
1296     GNUNET_RECLAIM_ATTRIBUTE_string_to_value (type,
1297                                               "Error: Referenced Claim Name not Found",
1298                                               (void **) &data,
1299                                               &data_size);
1300     attr = GNUNET_RECLAIM_ATTRIBUTE_claim_new (claim, type, data, data_size);
1301     attr->id = attest->id;
1302     attr->flag = 1;
1303   }
1304   else
1305   {
1306     attr = GNUNET_RECLAIM_ATTRIBUTE_claim_new (claim, type, data, data_size);
1307     attr->id = attest->id;
1308     attr->flag = 1;
1309   }
1310   return attr;
1311 }
1312
1313
1314 /**
1315  * Collect all attributes for an ego
1316  *
1317  */
1318 static void
1319 attr_collect (void *cls,
1320               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1321               const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
1322               const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest,
1323               const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference)
1324 {
1325   struct RequestHandle *handle = cls;
1326   json_t *attr_obj;
1327   const char *type;
1328   char *id_str;
1329
1330   if ((NULL == attr) && (NULL == reference))
1331   {
1332     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1333                 "Attribute Collection with empty Attribute/Reference\n");
1334     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
1335     return;
1336   }
1337
1338   if (NULL == attr)
1339   {
1340
1341     if ((NULL == reference->name) || (NULL == reference->reference_value))
1342     {
1343       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1344                   "Attribute Collection with empty Reference Name/Value\n");
1345       return;
1346     }
1347     struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr2;
1348     attr2 = parse_jwt (attest, reference->reference_value);
1349     if (NULL == attr2)
1350     {
1351       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1352                   "Attribute Collection with unparsed Attestation\n");
1353       return;
1354     }
1355     attr2->name = reference->name;
1356     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding reference as attribute: %s\n",
1357                 reference->name);
1358     char *tmp_value;
1359     tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr2->type,
1360                                                           attr2->data,
1361                                                           attr2->data_size);
1362     attr_obj = json_object ();
1363
1364     json_object_set_new (attr_obj, "value", json_string (tmp_value));
1365     json_object_set_new (attr_obj, "name", json_string (attr2->name));
1366     json_object_set_new (attr_obj, "flag", json_string ("1"));
1367     type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr2->type);
1368     json_object_set_new (attr_obj, "type", json_string (type));
1369     id_str = GNUNET_STRINGS_data_to_string_alloc (&attr2->id, sizeof(uint64_t));
1370     json_object_set_new (attr_obj, "id", json_string (id_str));
1371     json_array_append (handle->resp_object, attr_obj);
1372     json_decref (attr_obj);
1373     GNUNET_free (tmp_value);
1374   }
1375   else
1376   {
1377     if ((NULL == attr->name) || (NULL == attr->data))
1378     {
1379       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1380                   "Attribute Collection with empty Attribute Name/Value\n");
1381       GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
1382       return;
1383     }
1384     char *tmp_value;
1385     char *flag_str;
1386     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
1387
1388     tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
1389                                                           attr->data,
1390                                                           attr->data_size);
1391
1392     attr_obj = json_object ();
1393     json_object_set_new (attr_obj, "value", json_string (tmp_value));
1394     json_object_set_new (attr_obj, "name", json_string (attr->name));
1395     GNUNET_asprintf (&flag_str,"%d",attr->flag);
1396     json_object_set_new (attr_obj, "flag", json_string (flag_str));
1397     type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
1398     json_object_set_new (attr_obj, "type", json_string (type));
1399     id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(uint64_t));
1400     json_object_set_new (attr_obj, "id", json_string (id_str));
1401     json_array_append (handle->resp_object, attr_obj);
1402     json_decref (attr_obj);
1403     GNUNET_free (tmp_value);
1404     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
1405   }
1406 }
1407
1408 /**
1409  * List attributes for identity request
1410  *
1411  * @param con_handle the connection handle
1412  * @param url the url
1413  * @param cls the RequestHandle
1414  */
1415 static void
1416 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1417                      const char *url,
1418                      void *cls)
1419 {
1420   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1421   struct RequestHandle *handle = cls;
1422   struct EgoEntry *ego_entry;
1423   char *identity;
1424
1425   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1426               "Getting attributes for %s.\n",
1427               handle->url);
1428   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1429   {
1430     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1431     GNUNET_SCHEDULER_add_now (&do_error, handle);
1432     return;
1433   }
1434   identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
1435
1436   for (ego_entry = handle->ego_head; NULL != ego_entry;
1437        ego_entry = ego_entry->next)
1438     if (0 == strcmp (identity, ego_entry->identifier))
1439       break;
1440   handle->resp_object = json_array ();
1441
1442
1443   if (NULL == ego_entry)
1444   {
1445     // Done
1446     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1447     GNUNET_SCHEDULER_add_now (&return_response, handle);
1448     return;
1449   }
1450   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1451   handle->idp = GNUNET_RECLAIM_connect (cfg);
1452   handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
1453                                                          priv_key,
1454                                                          &collect_error_cb,
1455                                                          handle,
1456                                                          &attr_collect,
1457                                                          handle,
1458                                                          &collect_finished_cb,
1459                                                          handle);
1460 }
1461
1462
1463 /**
1464  * List attributes for identity request
1465  *
1466  * @param con_handle the connection handle
1467  * @param url the url
1468  * @param cls the RequestHandle
1469  */
1470 static void
1471 delete_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1472                        const char *url,
1473                        void *cls)
1474 {
1475   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1476   struct RequestHandle *handle = cls;
1477   struct GNUNET_RECLAIM_ATTRIBUTE_Claim attr;
1478   struct EgoEntry *ego_entry;
1479   char *identity_id_str;
1480   char *identity;
1481   char *id;
1482
1483   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attributes.\n");
1484   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1485   {
1486     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1487     GNUNET_SCHEDULER_add_now (&do_error, handle);
1488     return;
1489   }
1490   identity_id_str =
1491     strdup (handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1);
1492   identity = strtok (identity_id_str, "/");
1493   id = strtok (NULL, "/");
1494   if ((NULL == identity) || (NULL == id))
1495   {
1496     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
1497     GNUNET_free (identity_id_str);
1498     GNUNET_SCHEDULER_add_now (&do_error, handle);
1499     return;
1500   }
1501
1502   for (ego_entry = handle->ego_head; NULL != ego_entry;
1503        ego_entry = ego_entry->next)
1504     if (0 == strcmp (identity, ego_entry->identifier))
1505       break;
1506   handle->resp_object = json_array ();
1507   if (NULL == ego_entry)
1508   {
1509     // Done
1510     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1511     GNUNET_free (identity_id_str);
1512     GNUNET_SCHEDULER_add_now (&return_response, handle);
1513     return;
1514   }
1515   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1516   handle->idp = GNUNET_RECLAIM_connect (cfg);
1517   memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_Claim));
1518   GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(uint64_t));
1519   attr.name = "";
1520   handle->idp_op = GNUNET_RECLAIM_attribute_delete (handle->idp,
1521                                                     priv_key,
1522                                                     &attr,
1523                                                     &delete_finished_cb,
1524                                                     handle);
1525   GNUNET_free (identity_id_str);
1526 }
1527
1528
1529 static void
1530 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1531                     const char *url,
1532                     void *cls)
1533 {
1534   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1535   struct RequestHandle *handle = cls;
1536   struct EgoEntry *ego_entry;
1537   struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1538   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1539   char term_data[handle->rest_handle->data_size + 1];
1540   json_t *data_json;
1541   json_error_t err;
1542   struct GNUNET_JSON_Specification tktspec[] =
1543   { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1544
1545   if (0 >= handle->rest_handle->data_size)
1546   {
1547     GNUNET_SCHEDULER_add_now (&do_error, handle);
1548     return;
1549   }
1550
1551   term_data[handle->rest_handle->data_size] = '\0';
1552   GNUNET_memcpy (term_data,
1553                  handle->rest_handle->data,
1554                  handle->rest_handle->data_size);
1555   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1556   if ((NULL == data_json) ||
1557       (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)))
1558   {
1559     handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1560     GNUNET_SCHEDULER_add_now (&do_error, handle);
1561     GNUNET_JSON_parse_free (tktspec);
1562     if (NULL != data_json)
1563       json_decref (data_json);
1564     return;
1565   }
1566   json_decref (data_json);
1567   if (NULL == ticket)
1568   {
1569     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1570                 "Unable to parse ticket from %s\n",
1571                 term_data);
1572     GNUNET_SCHEDULER_add_now (&do_error, handle);
1573     return;
1574   }
1575
1576   for (ego_entry = handle->ego_head; NULL != ego_entry;
1577        ego_entry = ego_entry->next)
1578   {
1579     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1580     if (0 == memcmp (&ticket->identity,
1581                      &tmp_pk,
1582                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1583       break;
1584   }
1585   if (NULL == ego_entry)
1586   {
1587     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1588     GNUNET_JSON_parse_free (tktspec);
1589     return;
1590   }
1591   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1592
1593   handle->idp = GNUNET_RECLAIM_connect (cfg);
1594   handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
1595                                                  identity_priv,
1596                                                  ticket,
1597                                                  &finished_cont,
1598                                                  handle);
1599   GNUNET_JSON_parse_free (tktspec);
1600 }
1601
1602
1603 static void
1604 consume_cont (void *cls,
1605               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1606               const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
1607               const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest,
1608               const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference)
1609 {
1610   struct RequestHandle *handle = cls;
1611   char *val_str;
1612   json_t *value;
1613
1614   if (NULL == identity)
1615   {
1616     GNUNET_SCHEDULER_add_now (&return_response, handle);
1617     return;
1618   }
1619
1620   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
1621   val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
1622                                                       attr->data,
1623                                                       attr->data_size);
1624   if (NULL == val_str)
1625   {
1626     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1627                 "Failed to parse value for: %s\n",
1628                 attr->name);
1629     return;
1630   }
1631   value = json_string (val_str);
1632   json_object_set_new (handle->resp_object, attr->name, value);
1633   json_decref (value);
1634   GNUNET_free (val_str);
1635 }
1636
1637
1638 static void
1639 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1640                      const char *url,
1641                      void *cls)
1642 {
1643   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1644   struct RequestHandle *handle = cls;
1645   struct EgoEntry *ego_entry;
1646   struct GNUNET_RECLAIM_Ticket *ticket;
1647   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1648   char term_data[handle->rest_handle->data_size + 1];
1649   json_t *data_json;
1650   json_error_t err;
1651   struct GNUNET_JSON_Specification tktspec[] =
1652   { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1653
1654   if (0 >= handle->rest_handle->data_size)
1655   {
1656     GNUNET_SCHEDULER_add_now (&do_error, handle);
1657     return;
1658   }
1659
1660   term_data[handle->rest_handle->data_size] = '\0';
1661   GNUNET_memcpy (term_data,
1662                  handle->rest_handle->data,
1663                  handle->rest_handle->data_size);
1664   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1665   if (NULL == data_json)
1666   {
1667     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1668                 "Unable to parse JSON Object from %s\n",
1669                 term_data);
1670     GNUNET_SCHEDULER_add_now (&do_error, handle);
1671     return;
1672   }
1673   if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL))
1674   {
1675     handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1676     GNUNET_SCHEDULER_add_now (&do_error, handle);
1677     GNUNET_JSON_parse_free (tktspec);
1678     json_decref (data_json);
1679     return;
1680   }
1681   for (ego_entry = handle->ego_head; NULL != ego_entry;
1682        ego_entry = ego_entry->next)
1683   {
1684     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1685     if (0 == memcmp (&ticket->audience,
1686                      &tmp_pk,
1687                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1688       break;
1689   }
1690   if (NULL == ego_entry)
1691   {
1692     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1693     GNUNET_JSON_parse_free (tktspec);
1694     return;
1695   }
1696   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1697   handle->resp_object = json_object ();
1698   handle->idp = GNUNET_RECLAIM_connect (cfg);
1699   handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
1700                                                   identity_priv,
1701                                                   ticket,
1702                                                   &consume_cont,
1703                                                   handle);
1704   GNUNET_JSON_parse_free (tktspec);
1705 }
1706
1707
1708 /**
1709  * Respond to OPTIONS request
1710  *
1711  * @param con_handle the connection handle
1712  * @param url the url
1713  * @param cls the RequestHandle
1714  */
1715 static void
1716 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1717               const char *url,
1718               void *cls)
1719 {
1720   struct MHD_Response *resp;
1721   struct RequestHandle *handle = cls;
1722
1723   // For now, independent of path return all options
1724   resp = GNUNET_REST_create_response (NULL);
1725   MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
1726   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1727   cleanup_handle (handle);
1728   return;
1729 }
1730
1731
1732 /**
1733  * Handle rest request
1734  *
1735  * @param handle the request handle
1736  */
1737 static void
1738 init_cont (struct RequestHandle *handle)
1739 {
1740   struct GNUNET_REST_RequestHandlerError err;
1741   static const struct GNUNET_REST_RequestHandler handlers[] =
1742   { { MHD_HTTP_METHOD_GET,
1743       GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1744       &list_attribute_cont },
1745     { MHD_HTTP_METHOD_POST,
1746       GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1747       &add_attribute_cont },
1748     { MHD_HTTP_METHOD_DELETE,
1749       GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1750       &delete_attribute_cont },
1751     { MHD_HTTP_METHOD_GET,
1752       GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE,
1753       &list_attestation_cont },
1754     { MHD_HTTP_METHOD_POST,
1755       GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE,
1756       &add_attestation_cont },
1757     { MHD_HTTP_METHOD_DELETE,
1758       GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE,
1759       &delete_attestation_cont },
1760     { MHD_HTTP_METHOD_GET,
1761       GNUNET_REST_API_NS_IDENTITY_TICKETS,
1762       &list_tickets_cont },
1763     { MHD_HTTP_METHOD_POST,
1764       GNUNET_REST_API_NS_IDENTITY_REVOKE,
1765       &revoke_ticket_cont },
1766     { MHD_HTTP_METHOD_POST,
1767       GNUNET_REST_API_NS_IDENTITY_CONSUME,
1768       &consume_ticket_cont },
1769     { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, &options_cont },
1770     GNUNET_REST_HANDLER_END };
1771
1772   if (GNUNET_NO ==
1773       GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1774   {
1775     handle->response_code = err.error_code;
1776     GNUNET_SCHEDULER_add_now (&do_error, handle);
1777   }
1778 }
1779
1780
1781 /**
1782  * If listing is enabled, prints information about the egos.
1783  *
1784  * This function is initially called for all egos and then again
1785  * whenever a ego's identifier changes or if it is deleted.  At the
1786  * end of the initial pass over all egos, the function is once called
1787  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1788  * be invoked in the future or that there was an error.
1789  *
1790  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1791  * this function is only called ONCE, and 'NULL' being passed in
1792  * 'ego' does indicate an error (i.e. name is taken or no default
1793  * value is known).  If 'ego' is non-NULL and if '*ctx'
1794  * is set in those callbacks, the value WILL be passed to a subsequent
1795  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1796  * that one was not NULL).
1797  *
1798  * When an identity is renamed, this function is called with the
1799  * (known) ego but the NEW identifier.
1800  *
1801  * When an identity is deleted, this function is called with the
1802  * (known) ego and "NULL" for the 'identifier'.  In this case,
1803  * the 'ego' is henceforth invalid (and the 'ctx' should also be
1804  * cleaned up).
1805  *
1806  * @param cls closure
1807  * @param ego ego handle
1808  * @param ctx context for application to store data for this ego
1809  *                 (during the lifetime of this process, initially NULL)
1810  * @param identifier identifier assigned by the user for this ego,
1811  *                   NULL if the user just deleted the ego and it
1812  *                   must thus no longer be used
1813  */
1814 static void
1815 list_ego (void *cls,
1816           struct GNUNET_IDENTITY_Ego *ego,
1817           void **ctx,
1818           const char *identifier)
1819 {
1820   struct RequestHandle *handle = cls;
1821   struct EgoEntry *ego_entry;
1822   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1823
1824   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1825   {
1826     handle->state = ID_REST_STATE_POST_INIT;
1827     init_cont (handle);
1828     return;
1829   }
1830   if (ID_REST_STATE_INIT == handle->state)
1831   {
1832     ego_entry = GNUNET_new (struct EgoEntry);
1833     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1834     ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1835     ego_entry->ego = ego;
1836     ego_entry->identifier = GNUNET_strdup (identifier);
1837     GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
1838                                       handle->ego_tail,
1839                                       ego_entry);
1840   }
1841 }
1842
1843
1844 static void
1845 rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1846                                GNUNET_REST_ResultProcessor proc,
1847                                void *proc_cls)
1848 {
1849   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1850
1851   handle->response_code = 0;
1852   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1853   handle->proc_cls = proc_cls;
1854   handle->proc = proc;
1855   handle->state = ID_REST_STATE_INIT;
1856   handle->rest_handle = rest_handle;
1857
1858   handle->url = GNUNET_strdup (rest_handle->url);
1859   if (handle->url[strlen (handle->url) - 1] == '/')
1860     handle->url[strlen (handle->url) - 1] = '\0';
1861   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1862   handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
1863   handle->timeout_task =
1864     GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
1865   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1866 }
1867
1868
1869 /**
1870  * Entry point for the plugin.
1871  *
1872  * @param cls Config info
1873  * @return NULL on error, otherwise the plugin context
1874  */
1875 void *
1876 libgnunet_plugin_rest_reclaim_init (void *cls)
1877 {
1878   static struct Plugin plugin;
1879   struct GNUNET_REST_Plugin *api;
1880
1881   cfg = cls;
1882   if (NULL != plugin.cfg)
1883     return NULL; /* can only initialize once! */
1884   memset (&plugin, 0, sizeof(struct Plugin));
1885   plugin.cfg = cfg;
1886   api = GNUNET_new (struct GNUNET_REST_Plugin);
1887   api->cls = &plugin;
1888   api->name = GNUNET_REST_API_NS_RECLAIM;
1889   api->process_request = &rest_identity_process_request;
1890   GNUNET_asprintf (&allow_methods,
1891                    "%s, %s, %s, %s, %s",
1892                    MHD_HTTP_METHOD_GET,
1893                    MHD_HTTP_METHOD_POST,
1894                    MHD_HTTP_METHOD_PUT,
1895                    MHD_HTTP_METHOD_DELETE,
1896                    MHD_HTTP_METHOD_OPTIONS);
1897
1898   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1899               _ ("Identity Provider REST API initialized\n"));
1900   return api;
1901 }
1902
1903
1904 /**
1905  * Exit point from the plugin.
1906  *
1907  * @param cls the plugin context (as returned by "init")
1908  * @return always NULL
1909  */
1910 void *
1911 libgnunet_plugin_rest_reclaim_done (void *cls)
1912 {
1913   struct GNUNET_REST_Plugin *api = cls;
1914   struct Plugin *plugin = api->cls;
1915
1916   plugin->cfg = NULL;
1917
1918   GNUNET_free_non_null (allow_methods);
1919   GNUNET_free (api);
1920   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1921               "Identity Provider REST plugin is finished\n");
1922   return NULL;
1923 }
1924
1925
1926 /* end of plugin_rest_reclaim.c */