move to 256-bit identifier; some cleanups
[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(ticket->rnd));
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(ticket->rnd));
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 (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&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 (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id))
696     GNUNET_RECLAIM_id_generate (&attribute->id);
697   handle->idp = GNUNET_RECLAIM_connect (cfg);
698   exp = GNUNET_TIME_UNIT_HOURS;
699   handle->idp_op = GNUNET_RECLAIM_attestation_store (handle->idp,
700                                                      identity_priv,
701                                                      attribute,
702                                                      &exp,
703                                                      &finished_cont,
704                                                      handle);
705   GNUNET_JSON_parse_free (attrspec);
706 }
707
708 /**
709  * Collect all references for an ego
710  *
711  */
712 static void
713 ref_collect (void *cls,
714              const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
715              const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
716              const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest,
717              const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference)
718 {
719   struct RequestHandle *handle = cls;
720   json_t *attr_obj;
721   char *id_str;
722   char *id_attest_str;
723
724   if (NULL == reference)
725   {
726     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
727     return;
728   }
729
730   if ((NULL == reference->name) || (NULL == reference->reference_value))
731   {
732     return;
733   }
734
735   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding reference: %s\n",
736               reference->name);
737   attr_obj = json_object ();
738   json_object_set_new (attr_obj, "name", json_string (reference->name));
739   json_object_set_new (attr_obj, "ref_value", json_string (
740                          reference->reference_value));
741   id_str = GNUNET_STRINGS_data_to_string_alloc (&reference->id,
742                                                 sizeof(reference->id));
743   id_attest_str = GNUNET_STRINGS_data_to_string_alloc (&reference->id_attest,
744                                                        sizeof(reference->id_attest));
745   json_object_set_new (attr_obj, "id", json_string (id_str));
746   json_object_set_new (attr_obj, "ref_id", json_string (id_attest_str));
747   json_array_append (handle->resp_object, attr_obj);
748   json_decref (attr_obj);
749 }
750
751 /**
752  * Lists references for identity request
753  *
754  * @param con_handle the connection handle
755  * @param url the url
756  * @param cls the RequestHandle
757  */
758 static void
759 list_reference_cont (struct GNUNET_REST_RequestHandle *con_handle,
760                      const char *url,
761                      void *cls)
762 {
763   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
764   struct RequestHandle *handle = cls;
765   struct EgoEntry *ego_entry;
766   char *identity;
767
768   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
769               "Getting references for %s.\n",
770               handle->url);
771   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + strlen (
772         "reference/") + 1 >= strlen (
773         handle->url))
774   {
775     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
776     GNUNET_SCHEDULER_add_now (&do_error, handle);
777     return;
778   }
779   identity = handle->url + strlen (
780     GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + strlen ("reference/")
781              + 1;
782   for (ego_entry = handle->ego_head; NULL != ego_entry;
783        ego_entry = ego_entry->next)
784     if (0 == strcmp (identity, ego_entry->identifier))
785       break;
786   handle->resp_object = json_array ();
787
788   if (NULL == ego_entry)
789   {
790     // Done
791     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
792     GNUNET_SCHEDULER_add_now (&return_response, handle);
793     return;
794   }
795   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
796   handle->idp = GNUNET_RECLAIM_connect (cfg);
797   handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
798                                                          priv_key,
799                                                          &collect_error_cb,
800                                                          handle,
801                                                          &ref_collect,
802                                                          handle,
803                                                          &collect_finished_cb,
804                                                          handle);
805 }
806
807 /**
808  * Collect all attestations for an ego
809  *
810  */
811 static void
812 attest_collect (void *cls,
813                 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
814                 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
815                 const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest,
816                 const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference)
817 {
818   struct RequestHandle *handle = cls;
819   json_t *attr_obj;
820   const char *type;
821   char *tmp_value;
822   char *id_str;
823
824
825   if (NULL != reference)
826   {
827     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
828                 "Attestation Collection with Reference\n");
829     return;
830   }
831   if (NULL == attest)
832   {
833     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
834                 "Attestation Collection with empty Attestation\n");
835     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
836     return;
837   }
838
839   if ((NULL == attest->name) || (NULL == attest->data))
840   {
841     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
842                 "Attestation Collection with empty Name/Value\n");
843     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
844     return;
845   }
846
847   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attestation: %s\n",
848               attest->name);
849
850   tmp_value = GNUNET_RECLAIM_ATTESTATION_value_to_string (attest->type,
851                                                           attest->data,
852                                                           attest->data_size);
853   attr_obj = json_object ();
854   json_object_set_new (attr_obj, "value", json_string (tmp_value));
855   json_object_set_new (attr_obj, "name", json_string (attest->name));
856   type = GNUNET_RECLAIM_ATTESTATION_number_to_typename (attest->type);
857   json_object_set_new (attr_obj, "type", json_string (type));
858   id_str = GNUNET_STRINGS_data_to_string_alloc (&attest->id, sizeof(attest->id));
859   json_object_set_new (attr_obj, "id", json_string (id_str));
860   json_array_append (handle->resp_object, attr_obj);
861   json_decref (attr_obj);
862   GNUNET_free (tmp_value);
863   GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
864 }
865
866
867 /**
868  * Lists attestation for identity request
869  *
870  * @param con_handle the connection handle
871  * @param url the url
872  * @param cls the RequestHandle
873  */
874 static void
875 list_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
876                        const char *url,
877                        void *cls)
878 {
879   struct RequestHandle *handle = cls;
880   /* Check for substring "reference" */
881   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) < strlen (
882         handle->url))
883   {
884     if ( strncmp ("reference/", (handle->url + strlen (
885                                    GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE)
886                                  + 1), strlen (
887                     "reference/")) == 0)
888     {
889       list_reference_cont (con_handle,url,cls);
890       return;
891     }
892   }
893   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
894   struct EgoEntry *ego_entry;
895   char *identity;
896
897   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
898               "Getting attestations for %s.\n",
899               handle->url);
900   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) >= strlen (
901         handle->url))
902   {
903     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
904     GNUNET_SCHEDULER_add_now (&do_error, handle);
905     return;
906   }
907   identity = handle->url + strlen (
908     GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + 1;
909
910   for (ego_entry = handle->ego_head; NULL != ego_entry;
911        ego_entry = ego_entry->next)
912     if (0 == strcmp (identity, ego_entry->identifier))
913       break;
914   handle->resp_object = json_array ();
915
916
917   if (NULL == ego_entry)
918   {
919     // Done
920     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
921     GNUNET_SCHEDULER_add_now (&return_response, handle);
922     return;
923   }
924   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
925   handle->idp = GNUNET_RECLAIM_connect (cfg);
926   handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
927                                                          priv_key,
928                                                          &collect_error_cb,
929                                                          handle,
930                                                          &attest_collect,
931                                                          handle,
932                                                          &collect_finished_cb,
933                                                          handle);
934 }
935
936 /**
937  * Deletes reference from an identity
938  *
939  * @param con_handle the connection handle
940  * @param url the url
941  * @param cls the RequestHandle
942  */
943 static void
944 delete_attestation_ref_cont (struct GNUNET_REST_RequestHandle *con_handle,
945                              const char *url,
946                              void *cls)
947 {
948   struct RequestHandle *handle = cls;
949   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
950   struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr;
951   struct EgoEntry *ego_entry;
952   char *identity;
953   char *identity_id_str;
954   char *id;
955   char term_data[handle->rest_handle->data_size + 1];
956   json_t *data_json;
957   json_error_t err;
958
959   struct GNUNET_JSON_Specification attrspec[] =
960   { GNUNET_RECLAIM_JSON_spec_claim_attest_ref (&attr),
961     GNUNET_JSON_spec_end () };
962   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
963               "Deleting attestation reference.\n");
964   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + strlen (
965         "reference/") + 1 >= strlen (
966         handle->url))
967   {
968     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
969     GNUNET_SCHEDULER_add_now (&do_error, handle);
970     return;
971   }
972   identity_id_str = strdup (handle->url + strlen (
973                               GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE)
974                             + strlen ("reference/")
975                             + 1);
976   identity = strtok (identity_id_str, "/");
977   id = strtok (NULL, "/");
978
979   if ((NULL == identity) || (NULL == id))
980   {
981     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
982     GNUNET_SCHEDULER_add_now (&do_error, handle);
983     return;
984   }
985   for (ego_entry = handle->ego_head; NULL != ego_entry;
986        ego_entry = ego_entry->next)
987     if (0 == strcmp (identity, ego_entry->identifier))
988       break;
989   handle->resp_object = json_array ();
990   if (NULL == ego_entry)
991   {
992     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
993     GNUNET_SCHEDULER_add_now (&return_response, handle);
994     return;
995   }
996   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
997   if (0 >= handle->rest_handle->data_size)
998   {
999     GNUNET_SCHEDULER_add_now (&do_error, handle);
1000     return;
1001   }
1002
1003   term_data[handle->rest_handle->data_size] = '\0';
1004   GNUNET_memcpy (term_data,
1005                  handle->rest_handle->data,
1006                  handle->rest_handle->data_size);
1007   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1008   GNUNET_assert (GNUNET_OK ==
1009                  GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
1010   json_decref (data_json);
1011   if (NULL == attr)
1012   {
1013     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1014                 "Unable to parse attestation reference from %s\n",
1015                 term_data);
1016     GNUNET_SCHEDULER_add_now (&do_error, handle);
1017     return;
1018   }
1019   GNUNET_STRINGS_string_to_data (id, strlen (id), &attr->id, sizeof(attr->id));
1020
1021   handle->idp = GNUNET_RECLAIM_connect (cfg);
1022   handle->idp_op = GNUNET_RECLAIM_attestation_reference_delete (handle->idp,
1023                                                                 priv_key,
1024                                                                 attr,
1025                                                                 &
1026                                                                 delete_finished_cb,
1027                                                                 handle);
1028   GNUNET_JSON_parse_free (attrspec);
1029 }
1030
1031
1032 /**
1033  * Deletes attestation from an identity
1034  *
1035  * @param con_handle the connection handle
1036  * @param url the url
1037  * @param cls the RequestHandle
1038  */
1039 static void
1040 delete_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
1041                          const char *url,
1042                          void *cls)
1043 {
1044   struct RequestHandle *handle = cls;
1045   /* Check for substring "reference" */
1046   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) < strlen (
1047         handle->url))
1048   {
1049     if ( strncmp ("reference", (handle->url + strlen (
1050                                   GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE)
1051                                 + 1), strlen (
1052                     "reference")) == 0)
1053     {
1054       delete_attestation_ref_cont (con_handle,url,cls);
1055       return;
1056     }
1057   }
1058   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1059   struct GNUNET_RECLAIM_ATTESTATION_Claim attr;
1060   struct EgoEntry *ego_entry;
1061   char *identity_id_str;
1062   char *identity;
1063   char *id;
1064
1065   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attestation.\n");
1066   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) >= strlen (
1067         handle->url))
1068   {
1069     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1070     GNUNET_SCHEDULER_add_now (&do_error, handle);
1071     return;
1072   }
1073   identity_id_str =
1074     strdup (handle->url + strlen (
1075               GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + 1);
1076   identity = strtok (identity_id_str, "/");
1077   id = strtok (NULL, "/");
1078   if ((NULL == identity) || (NULL == id))
1079   {
1080     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
1081     GNUNET_free (identity_id_str);
1082     GNUNET_SCHEDULER_add_now (&do_error, handle);
1083     return;
1084   }
1085
1086   for (ego_entry = handle->ego_head; NULL != ego_entry;
1087        ego_entry = ego_entry->next)
1088     if (0 == strcmp (identity, ego_entry->identifier))
1089       break;
1090   handle->resp_object = json_array ();
1091   if (NULL == ego_entry)
1092   {
1093     // Done
1094     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1095     GNUNET_free (identity_id_str);
1096     GNUNET_SCHEDULER_add_now (&return_response, handle);
1097     return;
1098   }
1099   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1100   handle->idp = GNUNET_RECLAIM_connect (cfg);
1101   memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_ATTESTATION_Claim));
1102   GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
1103   attr.name = "";
1104   handle->idp_op = GNUNET_RECLAIM_attestation_delete (handle->idp,
1105                                                       priv_key,
1106                                                       &attr,
1107                                                       &delete_finished_cb,
1108                                                       handle);
1109   GNUNET_free (identity_id_str);
1110 }
1111
1112 /**
1113  * List tickets for identity request
1114  *
1115  * @param con_handle the connection handle
1116  * @param url the url
1117  * @param cls the RequestHandle
1118  */
1119 static void
1120 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
1121                    const char *url,
1122                    void *cls)
1123 {
1124   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1125   struct RequestHandle *handle = cls;
1126   struct EgoEntry *ego_entry;
1127   char *identity;
1128
1129   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1130               "Getting tickets for %s.\n",
1131               handle->url);
1132   if (strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= strlen (handle->url))
1133   {
1134     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1135     GNUNET_SCHEDULER_add_now (&do_error, handle);
1136     return;
1137   }
1138   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
1139
1140   for (ego_entry = handle->ego_head; NULL != ego_entry;
1141        ego_entry = ego_entry->next)
1142     if (0 == strcmp (identity, ego_entry->identifier))
1143       break;
1144   handle->resp_object = json_array ();
1145
1146   if (NULL == ego_entry)
1147   {
1148     // Done
1149     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1150     GNUNET_SCHEDULER_add_now (&return_response, handle);
1151     return;
1152   }
1153   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1154   handle->idp = GNUNET_RECLAIM_connect (cfg);
1155   handle->ticket_it =
1156     GNUNET_RECLAIM_ticket_iteration_start (handle->idp,
1157                                            priv_key,
1158                                            &collect_error_cb,
1159                                            handle,
1160                                            &ticket_collect,
1161                                            handle,
1162                                            &collect_finished_cb,
1163                                            handle);
1164 }
1165
1166
1167 static void
1168 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1169                     const char *url,
1170                     void *cls)
1171 {
1172   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1173   const char *identity;
1174   struct RequestHandle *handle = cls;
1175   struct EgoEntry *ego_entry;
1176   struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute;
1177   struct GNUNET_TIME_Relative exp;
1178   char term_data[handle->rest_handle->data_size + 1];
1179   json_t *data_json;
1180   json_error_t err;
1181   struct GNUNET_JSON_Specification attrspec[] =
1182   { GNUNET_RECLAIM_JSON_spec_claim (&attribute), GNUNET_JSON_spec_end () };
1183
1184   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1185               "Adding an attribute for %s.\n",
1186               handle->url);
1187   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1188   {
1189     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1190     GNUNET_SCHEDULER_add_now (&do_error, handle);
1191     return;
1192   }
1193   identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
1194
1195   for (ego_entry = handle->ego_head; NULL != ego_entry;
1196        ego_entry = ego_entry->next)
1197     if (0 == strcmp (identity, ego_entry->identifier))
1198       break;
1199
1200   if (NULL == ego_entry)
1201   {
1202     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
1203     return;
1204   }
1205   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1206
1207   if (0 >= handle->rest_handle->data_size)
1208   {
1209     GNUNET_SCHEDULER_add_now (&do_error, handle);
1210     return;
1211   }
1212
1213   term_data[handle->rest_handle->data_size] = '\0';
1214   GNUNET_memcpy (term_data,
1215                  handle->rest_handle->data,
1216                  handle->rest_handle->data_size);
1217   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1218   GNUNET_assert (GNUNET_OK ==
1219                  GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
1220   json_decref (data_json);
1221   if (NULL == attribute)
1222   {
1223     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1224                 "Unable to parse attribute from %s\n",
1225                 term_data);
1226     GNUNET_SCHEDULER_add_now (&do_error, handle);
1227     return;
1228   }
1229   /**
1230    * New ID for attribute
1231    */
1232   if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id))
1233     GNUNET_RECLAIM_id_generate (&attribute->id);
1234   handle->idp = GNUNET_RECLAIM_connect (cfg);
1235   exp = GNUNET_TIME_UNIT_HOURS;
1236   handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
1237                                                    identity_priv,
1238                                                    attribute,
1239                                                    &exp,
1240                                                    &finished_cont,
1241                                                    handle);
1242   GNUNET_JSON_parse_free (attrspec);
1243 }
1244
1245 /**
1246  * Parse a JWT and return the respective claim value as Attribute
1247  *
1248  * @param attest the jwt attestation
1249  * @param claim the name of the claim in the JWT
1250  *
1251  * @return a GNUNET_RECLAIM_ATTRIBUTE_Claim, containing the new value
1252  */
1253 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *
1254 parse_jwt (const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest,
1255            const char *claim)
1256 {
1257   char *jwt_string;
1258   struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr;
1259   char delim[] = ".";
1260   const char *type_str = NULL;
1261   const char *val_str = NULL;
1262   char *data;
1263   size_t data_size;
1264   uint32_t type;
1265   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing JWT attributes.\n");
1266   char *decoded_jwt;
1267   json_t *json_val;
1268   json_error_t *json_err = NULL;
1269
1270   jwt_string = GNUNET_RECLAIM_ATTESTATION_value_to_string (attest->type,
1271                                                            attest->data,
1272                                                            attest->data_size);
1273   char *jwt_body = strtok (jwt_string, delim);
1274   jwt_body = strtok (NULL, delim);
1275   GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body),
1276                                 (void **) &decoded_jwt);
1277   json_val = json_loads (decoded_jwt, JSON_DECODE_ANY, json_err);
1278   const char *key;
1279   json_t *value;
1280   json_object_foreach (json_val, key, value) {
1281     if (0 == strcasecmp (key,claim))
1282     {
1283       val_str = json_dumps (value, JSON_ENCODE_ANY);
1284     }
1285   }
1286   type_str = "String";
1287   type = GNUNET_RECLAIM_ATTRIBUTE_typename_to_number (type_str);
1288   if (GNUNET_SYSERR ==(GNUNET_RECLAIM_ATTRIBUTE_string_to_value (type,val_str,
1289                                                                  (void **) &data,
1290                                                                  &data_size)))
1291   {
1292     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1293                 "Attribute value from JWT Parser invalid!\n");
1294     GNUNET_RECLAIM_ATTRIBUTE_string_to_value (type,
1295                                               "Error: Referenced Claim Name not Found",
1296                                               (void **) &data,
1297                                               &data_size);
1298     attr = GNUNET_RECLAIM_ATTRIBUTE_claim_new (claim, type, data, data_size);
1299     attr->id = attest->id;
1300     attr->flag = 1;
1301   }
1302   else
1303   {
1304     attr = GNUNET_RECLAIM_ATTRIBUTE_claim_new (claim, type, data, data_size);
1305     attr->id = attest->id;
1306     attr->flag = 1;
1307   }
1308   return attr;
1309 }
1310
1311
1312 /**
1313  * Collect all attributes for an ego
1314  *
1315  */
1316 static void
1317 attr_collect (void *cls,
1318               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1319               const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
1320               const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest,
1321               const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference)
1322 {
1323   struct RequestHandle *handle = cls;
1324   json_t *attr_obj;
1325   const char *type;
1326   char *id_str;
1327
1328   if ((NULL == attr) && (NULL == reference))
1329   {
1330     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1331                 "Attribute Collection with empty Attribute/Reference\n");
1332     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
1333     return;
1334   }
1335
1336   if (NULL == attr)
1337   {
1338
1339     if ((NULL == reference->name) || (NULL == reference->reference_value))
1340     {
1341       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1342                   "Attribute Collection with empty Reference Name/Value\n");
1343       return;
1344     }
1345     struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr2;
1346     attr2 = parse_jwt (attest, reference->reference_value);
1347     if (NULL == attr2)
1348     {
1349       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1350                   "Attribute Collection with unparsed Attestation\n");
1351       return;
1352     }
1353     attr2->name = reference->name;
1354     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding reference as attribute: %s\n",
1355                 reference->name);
1356     char *tmp_value;
1357     tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr2->type,
1358                                                           attr2->data,
1359                                                           attr2->data_size);
1360     attr_obj = json_object ();
1361
1362     json_object_set_new (attr_obj, "value", json_string (tmp_value));
1363     json_object_set_new (attr_obj, "name", json_string (attr2->name));
1364     json_object_set_new (attr_obj, "flag", json_string ("1"));
1365     type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr2->type);
1366     json_object_set_new (attr_obj, "type", json_string (type));
1367     id_str = GNUNET_STRINGS_data_to_string_alloc (&attr2->id,
1368                                                   sizeof(attr2->id));
1369     json_object_set_new (attr_obj, "id", json_string (id_str));
1370     json_array_append (handle->resp_object, attr_obj);
1371     json_decref (attr_obj);
1372     GNUNET_free (tmp_value);
1373   }
1374   else
1375   {
1376     if ((NULL == attr->name) || (NULL == attr->data))
1377     {
1378       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1379                   "Attribute Collection with empty Attribute Name/Value\n");
1380       GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
1381       return;
1382     }
1383     char *tmp_value;
1384     char *flag_str;
1385     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
1386
1387     tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
1388                                                           attr->data,
1389                                                           attr->data_size);
1390
1391     attr_obj = json_object ();
1392     json_object_set_new (attr_obj, "value", json_string (tmp_value));
1393     json_object_set_new (attr_obj, "name", json_string (attr->name));
1394     GNUNET_asprintf (&flag_str,"%d",attr->flag);
1395     json_object_set_new (attr_obj, "flag", json_string (flag_str));
1396     type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
1397     json_object_set_new (attr_obj, "type", json_string (type));
1398     id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id,
1399                                                   sizeof(attr->id));
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(attr.id));
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 */