6f7a5987b4b111a154045e39f65eecd02f3fd14c
[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 "/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_AttributeList *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    * Attribute iterator
194    */
195   struct GNUNET_RECLAIM_AttestationIterator *attest_it;
196
197
198   /**
199    * Ticket iterator
200    */
201   struct GNUNET_RECLAIM_TicketIterator *ticket_it;
202
203   /**
204    * A ticket
205    */
206   struct GNUNET_RECLAIM_Ticket ticket;
207
208   /**
209    * Desired timeout for the lookup (default is no timeout).
210    */
211   struct GNUNET_TIME_Relative timeout;
212
213   /**
214    * ID of a task associated with the resolution process.
215    */
216   struct GNUNET_SCHEDULER_Task *timeout_task;
217
218   /**
219    * The plugin result processor
220    */
221   GNUNET_REST_ResultProcessor proc;
222
223   /**
224    * The closure of the result processor
225    */
226   void *proc_cls;
227
228   /**
229    * The url
230    */
231   char *url;
232
233   /**
234    * Error response message
235    */
236   char *emsg;
237
238   /**
239    * Reponse code
240    */
241   int response_code;
242
243   /**
244    * Response object
245    */
246   json_t *resp_object;
247 };
248
249 /**
250  * Cleanup lookup handle
251  * @param handle Handle to clean up
252  */
253 static void
254 cleanup_handle (struct RequestHandle *handle)
255 {
256   struct EgoEntry *ego_entry;
257   struct EgoEntry *ego_tmp;
258
259   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
260   if (NULL != handle->resp_object)
261     json_decref (handle->resp_object);
262   if (NULL != handle->timeout_task)
263     GNUNET_SCHEDULER_cancel (handle->timeout_task);
264   if (NULL != handle->identity_handle)
265     GNUNET_IDENTITY_disconnect (handle->identity_handle);
266   if (NULL != handle->attr_it)
267     GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
268   if (NULL != handle->attest_it)
269     GNUNET_RECLAIM_get_attestations_stop (handle->attest_it);
270   if (NULL != handle->ticket_it)
271     GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
272   if (NULL != handle->idp)
273     GNUNET_RECLAIM_disconnect (handle->idp);
274   if (NULL != handle->url)
275     GNUNET_free (handle->url);
276   if (NULL != handle->emsg)
277     GNUNET_free (handle->emsg);
278   GNUNET_RECLAIM_attribute_list_destroy (handle->attr_list);
279   for (ego_entry = handle->ego_head; NULL != ego_entry;)
280   {
281     ego_tmp = ego_entry;
282     ego_entry = ego_entry->next;
283     GNUNET_free (ego_tmp->identifier);
284     GNUNET_free (ego_tmp->keystring);
285     GNUNET_free (ego_tmp);
286   }
287   GNUNET_free (handle);
288 }
289
290
291 static void
292 cleanup_handle_delayed (void *cls)
293 {
294   cleanup_handle (cls);
295 }
296
297
298 /**
299  * Task run on error, sends error message.  Cleans up everything.
300  *
301  * @param cls the `struct RequestHandle`
302  */
303 static void
304 do_error (void *cls)
305 {
306   struct RequestHandle *handle = cls;
307   struct MHD_Response *resp;
308   char *json_error;
309
310   GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", handle->emsg);
311   if (0 == handle->response_code)
312   {
313     handle->response_code = MHD_HTTP_BAD_REQUEST;
314   }
315   resp = GNUNET_REST_create_response (json_error);
316   MHD_add_response_header (resp, "Content-Type", "application/json");
317   handle->proc (handle->proc_cls, resp, handle->response_code);
318   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
319   GNUNET_free (json_error);
320 }
321
322
323 /**
324  * Task run on timeout, sends error message.  Cleans up everything.
325  *
326  * @param cls the `struct RequestHandle`
327  */
328 static void
329 do_timeout (void *cls)
330 {
331   struct RequestHandle *handle = cls;
332
333   handle->timeout_task = NULL;
334   do_error (handle);
335 }
336
337
338 static void
339 collect_error_cb (void *cls)
340 {
341   struct RequestHandle *handle = cls;
342
343   do_error (handle);
344 }
345
346
347 static void
348 finished_cont (void *cls, int32_t success, const char *emsg)
349 {
350   struct RequestHandle *handle = cls;
351   struct MHD_Response *resp;
352
353   resp = GNUNET_REST_create_response (emsg);
354   if (GNUNET_OK != success)
355   {
356     GNUNET_SCHEDULER_add_now (&do_error, handle);
357     return;
358   }
359   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
360   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
361 }
362
363
364 static void
365 delete_finished_cb (void *cls, int32_t success, const char *emsg)
366 {
367   struct RequestHandle *handle = cls;
368   struct MHD_Response *resp;
369
370   resp = GNUNET_REST_create_response (emsg);
371   if (GNUNET_OK != success)
372   {
373     GNUNET_SCHEDULER_add_now (&do_error, handle);
374     return;
375   }
376   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
377   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
378 }
379
380
381 /**
382  * Return attributes for identity
383  *
384  * @param cls the request handle
385  */
386 static void
387 return_response (void *cls)
388 {
389   char *result_str;
390   struct RequestHandle *handle = cls;
391   struct MHD_Response *resp;
392
393   result_str = json_dumps (handle->resp_object, 0);
394   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
395   resp = GNUNET_REST_create_response (result_str);
396   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
397   GNUNET_free (result_str);
398   cleanup_handle (handle);
399 }
400
401
402 static void
403 collect_finished_cb (void *cls)
404 {
405   struct RequestHandle *handle = cls;
406
407   // Done
408   handle->attr_it = NULL;
409   handle->ticket_it = NULL;
410   GNUNET_SCHEDULER_add_now (&return_response, handle);
411 }
412
413
414 /**
415  * Collect all attributes for an ego
416  *
417  */
418 static void
419 ticket_collect (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
420 {
421   json_t *json_resource;
422   struct RequestHandle *handle = cls;
423   json_t *value;
424   char *tmp;
425
426   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
427   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(ticket->rnd));
428   json_resource = json_object ();
429   GNUNET_free (tmp);
430   json_array_append (handle->resp_object, json_resource);
431
432   tmp =
433     GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
434                                          sizeof(struct
435                                                 GNUNET_CRYPTO_EcdsaPublicKey));
436   value = json_string (tmp);
437   json_object_set_new (json_resource, "issuer", value);
438   GNUNET_free (tmp);
439   tmp =
440     GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
441                                          sizeof(struct
442                                                 GNUNET_CRYPTO_EcdsaPublicKey));
443   value = json_string (tmp);
444   json_object_set_new (json_resource, "audience", value);
445   GNUNET_free (tmp);
446   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(ticket->rnd));
447   value = json_string (tmp);
448   json_object_set_new (json_resource, "rnd", value);
449   GNUNET_free (tmp);
450   GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it);
451 }
452
453
454 static void
455 parse_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
456                         const char *url,
457                         void *cls)
458 {
459   struct RequestHandle *handle = cls;
460
461   char term_data[handle->rest_handle->data_size + 1];
462   json_t *data_json;
463   json_error_t err;
464   int unpack_state;
465   struct MHD_Response *resp;
466   char *val_str = NULL;
467   const char *type_str = NULL;
468   term_data[handle->rest_handle->data_size] = '\0';
469   GNUNET_memcpy (term_data,
470                  handle->rest_handle->data,
471                  handle->rest_handle->data_size);
472   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
473   GNUNET_assert (NULL != data_json);
474   if (! json_is_object (data_json))
475   {
476     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
477                 "Error json is not array nor object!\n");
478     GNUNET_SCHEDULER_add_now (&do_error, handle);
479     return;
480   }
481   unpack_state = json_unpack (data_json,
482                               "{s:s, s:s!}",
483                               "value",
484                               &val_str,
485                               "type",
486                               &type_str);
487   if ((0 != unpack_state) || (NULL == val_str) || (NULL == type_str))
488   {
489     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
490                 "Error json object has a wrong format!\n");
491     GNUNET_SCHEDULER_add_now (&do_error, handle);
492     return;
493   }
494   if (0 == strcmp (type_str, "JWT"))
495   {
496     // The value is a JWT
497     char *decoded_jwt;
498     char delim[] = ".";
499     char *jwt_body = strtok (val_str, delim);
500     jwt_body = strtok (NULL, delim);
501     GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body),
502                                   (void **) &decoded_jwt);
503     resp = GNUNET_REST_create_response (decoded_jwt);
504     handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
505     GNUNET_free (decoded_jwt);
506   }
507   else
508   {
509     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
510                 "Error requested parsing type not supported!\n");
511     GNUNET_SCHEDULER_add_now (&do_error, handle);
512     return;
513   }
514   cleanup_handle (handle);
515   json_decref (data_json);
516 }
517
518
519 static void
520 add_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
521                       const char *url,
522                       void *cls)
523 {
524   struct RequestHandle *handle = cls;
525   /* Check for substring "parse"
526    * FIXME UGLY! */
527   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) < strlen (
528         handle->url))
529   {
530     if (strncmp ("parse", (handle->url + strlen (
531                              GNUNET_REST_API_NS_RECLAIM_ATTESTATION)
532                            + 1), strlen (
533                    "parse")) == 0)
534     {
535       parse_attestation_cont (con_handle,url,cls);
536       return;
537     }
538   }
539   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
540   const char *identity;
541   struct EgoEntry *ego_entry;
542   struct GNUNET_RECLAIM_Attestation *attribute;
543   struct GNUNET_TIME_Relative exp;
544   char term_data[handle->rest_handle->data_size + 1];
545   json_t *data_json;
546   json_error_t err;
547   struct GNUNET_JSON_Specification attrspec[] =
548   { GNUNET_RECLAIM_JSON_spec_claim_attest (&attribute),
549     GNUNET_JSON_spec_end () };
550
551   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
552               "Adding an attestation for %s.\n",
553               handle->url);
554   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
555         handle->url))
556   {
557     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
558     GNUNET_SCHEDULER_add_now (&do_error, handle);
559     return;
560   }
561   identity = handle->url + strlen (
562     GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1;
563
564   for (ego_entry = handle->ego_head; NULL != ego_entry;
565        ego_entry = ego_entry->next)
566     if (0 == strcmp (identity, ego_entry->identifier))
567       break;
568
569   if (NULL == ego_entry)
570   {
571     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
572     return;
573   }
574   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
575
576   if (0 >= handle->rest_handle->data_size)
577   {
578     GNUNET_SCHEDULER_add_now (&do_error, handle);
579     return;
580   }
581
582   term_data[handle->rest_handle->data_size] = '\0';
583   GNUNET_memcpy (term_data,
584                  handle->rest_handle->data,
585                  handle->rest_handle->data_size);
586   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
587   GNUNET_assert (GNUNET_OK ==
588                  GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
589   json_decref (data_json);
590   if (NULL == attribute)
591   {
592     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
593                 "Unable to parse attestation from %s\n",
594                 term_data);
595     GNUNET_SCHEDULER_add_now (&do_error, handle);
596     return;
597   }
598   /**
599    * New ID for attribute
600    */
601   if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id))
602     GNUNET_RECLAIM_id_generate (&attribute->id);
603   handle->idp = GNUNET_RECLAIM_connect (cfg);
604   exp = GNUNET_TIME_UNIT_HOURS;
605   handle->idp_op = GNUNET_RECLAIM_attestation_store (handle->idp,
606                                                      identity_priv,
607                                                      attribute,
608                                                      &exp,
609                                                      &finished_cont,
610                                                      handle);
611   GNUNET_JSON_parse_free (attrspec);
612 }
613
614
615 /**
616  * Collect all attestations for an ego
617  *
618  */
619 static void
620 attest_collect (void *cls,
621                 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
622                 const struct GNUNET_RECLAIM_Attestation *attest)
623 {
624   struct RequestHandle *handle = cls;
625   json_t *attr_obj;
626   const char *type;
627   char *tmp_value;
628   char *id_str;
629
630
631   if (NULL == attest)
632   {
633     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634                 "Attestation Collection with empty Attestation\n");
635     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
636     return;
637   }
638
639   if ((NULL == attest->name) || (NULL == attest->data))
640   {
641     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
642                 "Attestation Collection with empty Name/Value\n");
643     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
644     return;
645   }
646
647   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attestation: %s\n",
648               attest->name);
649
650   tmp_value = GNUNET_RECLAIM_attestation_value_to_string (attest->type,
651                                                           attest->data,
652                                                           attest->data_size);
653   attr_obj = json_object ();
654   json_object_set_new (attr_obj, "value", json_string (tmp_value));
655   json_object_set_new (attr_obj, "name", json_string (attest->name));
656   type = GNUNET_RECLAIM_attestation_number_to_typename (attest->type);
657   json_object_set_new (attr_obj, "type", json_string (type));
658   id_str = GNUNET_STRINGS_data_to_string_alloc (&attest->id,
659                                                 sizeof(attest->id));
660   json_object_set_new (attr_obj, "id", json_string (id_str));
661   json_array_append (handle->resp_object, attr_obj);
662   json_decref (attr_obj);
663   GNUNET_free (tmp_value);
664   GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
665 }
666
667
668 /**
669  * Lists attestation for identity request
670  *
671  * @param con_handle the connection handle
672  * @param url the url
673  * @param cls the RequestHandle
674  */
675 static void
676 list_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
677                        const char *url,
678                        void *cls)
679 {
680   struct RequestHandle *handle = cls;
681   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
682   struct EgoEntry *ego_entry;
683   char *identity;
684
685   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
686               "Getting attestations for %s.\n",
687               handle->url);
688   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
689         handle->url))
690   {
691     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
692     GNUNET_SCHEDULER_add_now (&do_error, handle);
693     return;
694   }
695   identity = handle->url + strlen (
696     GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1;
697
698   for (ego_entry = handle->ego_head; NULL != ego_entry;
699        ego_entry = ego_entry->next)
700     if (0 == strcmp (identity, ego_entry->identifier))
701       break;
702   handle->resp_object = json_array ();
703
704
705   if (NULL == ego_entry)
706   {
707     // Done
708     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
709     GNUNET_SCHEDULER_add_now (&return_response, handle);
710     return;
711   }
712   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
713   handle->idp = GNUNET_RECLAIM_connect (cfg);
714   handle->attest_it = GNUNET_RECLAIM_get_attestations_start (handle->idp,
715                                                              priv_key,
716                                                              &collect_error_cb,
717                                                              handle,
718                                                              &attest_collect,
719                                                              handle,
720                                                              &
721                                                              collect_finished_cb,
722                                                              handle);
723 }
724
725
726 /**
727  * Deletes attestation from an identity
728  *
729  * @param con_handle the connection handle
730  * @param url the url
731  * @param cls the RequestHandle
732  */
733 static void
734 delete_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
735                          const char *url,
736                          void *cls)
737 {
738   struct RequestHandle *handle = cls;
739   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
740   struct GNUNET_RECLAIM_Attestation attr;
741   struct EgoEntry *ego_entry;
742   char *identity_id_str;
743   char *identity;
744   char *id;
745
746   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attestation.\n");
747   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
748         handle->url))
749   {
750     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
751     GNUNET_SCHEDULER_add_now (&do_error, handle);
752     return;
753   }
754   identity_id_str =
755     strdup (handle->url + strlen (
756               GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1);
757   identity = strtok (identity_id_str, "/");
758   id = strtok (NULL, "/");
759   if ((NULL == identity) || (NULL == id))
760   {
761     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
762     GNUNET_free (identity_id_str);
763     GNUNET_SCHEDULER_add_now (&do_error, handle);
764     return;
765   }
766
767   for (ego_entry = handle->ego_head; NULL != ego_entry;
768        ego_entry = ego_entry->next)
769     if (0 == strcmp (identity, ego_entry->identifier))
770       break;
771   handle->resp_object = json_array ();
772   if (NULL == ego_entry)
773   {
774     // Done
775     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
776     GNUNET_free (identity_id_str);
777     GNUNET_SCHEDULER_add_now (&return_response, handle);
778     return;
779   }
780   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
781   handle->idp = GNUNET_RECLAIM_connect (cfg);
782   memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Attestation));
783   GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
784   attr.name = "";
785   handle->idp_op = GNUNET_RECLAIM_attestation_delete (handle->idp,
786                                                       priv_key,
787                                                       &attr,
788                                                       &delete_finished_cb,
789                                                       handle);
790   GNUNET_free (identity_id_str);
791 }
792
793
794 /**
795  * List tickets for identity request
796  *
797  * @param con_handle the connection handle
798  * @param url the url
799  * @param cls the RequestHandle
800  */
801 static void
802 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
803                    const char *url,
804                    void *cls)
805 {
806   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
807   struct RequestHandle *handle = cls;
808   struct EgoEntry *ego_entry;
809   char *identity;
810
811   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
812               "Getting tickets for %s.\n",
813               handle->url);
814   if (strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= strlen (handle->url))
815   {
816     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
817     GNUNET_SCHEDULER_add_now (&do_error, handle);
818     return;
819   }
820   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
821
822   for (ego_entry = handle->ego_head; NULL != ego_entry;
823        ego_entry = ego_entry->next)
824     if (0 == strcmp (identity, ego_entry->identifier))
825       break;
826   handle->resp_object = json_array ();
827
828   if (NULL == ego_entry)
829   {
830     // Done
831     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
832     GNUNET_SCHEDULER_add_now (&return_response, handle);
833     return;
834   }
835   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
836   handle->idp = GNUNET_RECLAIM_connect (cfg);
837   handle->ticket_it =
838     GNUNET_RECLAIM_ticket_iteration_start (handle->idp,
839                                            priv_key,
840                                            &collect_error_cb,
841                                            handle,
842                                            &ticket_collect,
843                                            handle,
844                                            &collect_finished_cb,
845                                            handle);
846 }
847
848
849 static void
850 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
851                     const char *url,
852                     void *cls)
853 {
854   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
855   const char *identity;
856   struct RequestHandle *handle = cls;
857   struct EgoEntry *ego_entry;
858   struct GNUNET_RECLAIM_Attribute *attribute;
859   struct GNUNET_TIME_Relative exp;
860   char term_data[handle->rest_handle->data_size + 1];
861   json_t *data_json;
862   json_error_t err;
863   struct GNUNET_JSON_Specification attrspec[] =
864   { GNUNET_RECLAIM_JSON_spec_claim (&attribute), GNUNET_JSON_spec_end () };
865
866   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
867               "Adding an attribute for %s.\n",
868               handle->url);
869   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
870   {
871     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
872     GNUNET_SCHEDULER_add_now (&do_error, handle);
873     return;
874   }
875   identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
876
877   for (ego_entry = handle->ego_head; NULL != ego_entry;
878        ego_entry = ego_entry->next)
879     if (0 == strcmp (identity, ego_entry->identifier))
880       break;
881
882   if (NULL == ego_entry)
883   {
884     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
885     return;
886   }
887   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
888
889   if (0 >= handle->rest_handle->data_size)
890   {
891     GNUNET_SCHEDULER_add_now (&do_error, handle);
892     return;
893   }
894
895   term_data[handle->rest_handle->data_size] = '\0';
896   GNUNET_memcpy (term_data,
897                  handle->rest_handle->data,
898                  handle->rest_handle->data_size);
899   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
900   GNUNET_assert (GNUNET_OK ==
901                  GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
902   json_decref (data_json);
903   if (NULL == attribute)
904   {
905     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
906                 "Unable to parse attribute from %s\n",
907                 term_data);
908     GNUNET_SCHEDULER_add_now (&do_error, handle);
909     return;
910   }
911   /**
912    * New ID for attribute
913    */
914   if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id))
915     GNUNET_RECLAIM_id_generate (&attribute->id);
916   handle->idp = GNUNET_RECLAIM_connect (cfg);
917   exp = GNUNET_TIME_UNIT_HOURS;
918   handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
919                                                    identity_priv,
920                                                    attribute,
921                                                    &exp,
922                                                    &finished_cont,
923                                                    handle);
924   GNUNET_JSON_parse_free (attrspec);
925 }
926
927
928 /**
929  * Parse a JWT and return the respective claim value as Attribute
930  *
931  * @param attest the jwt attestation
932  * @param claim the name of the claim in the JWT
933  *
934  * @return a GNUNET_RECLAIM_Attribute, containing the new value
935  */
936 struct GNUNET_RECLAIM_Attribute *
937 parse_jwt (const struct GNUNET_RECLAIM_Attestation *attest,
938            const char *claim)
939 {
940   char *jwt_string;
941   struct GNUNET_RECLAIM_Attribute *attr;
942   char delim[] = ".";
943   const char *type_str = NULL;
944   const char *val_str = NULL;
945   char *data;
946   size_t data_size;
947   uint32_t type;
948   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing JWT attributes.\n");
949   char *decoded_jwt;
950   json_t *json_val;
951   json_error_t *json_err = NULL;
952
953   jwt_string = GNUNET_RECLAIM_attestation_value_to_string (attest->type,
954                                                            attest->data,
955                                                            attest->data_size);
956   char *jwt_body = strtok (jwt_string, delim);
957   jwt_body = strtok (NULL, delim);
958   GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body),
959                                 (void **) &decoded_jwt);
960   json_val = json_loads (decoded_jwt, JSON_DECODE_ANY, json_err);
961   const char *key;
962   json_t *value;
963   json_object_foreach (json_val, key, value) {
964     if (0 == strcasecmp (key,claim))
965     {
966       val_str = json_dumps (value, JSON_ENCODE_ANY);
967     }
968   }
969   type_str = "String";
970   type = GNUNET_RECLAIM_attribute_typename_to_number (type_str);
971   if (GNUNET_SYSERR == GNUNET_RECLAIM_attribute_string_to_value (type,val_str,
972                                                                  (void **) &data,
973                                                                  &data_size))
974   {
975     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
976                 "Attribute value from JWT Parser invalid!\n");
977     GNUNET_RECLAIM_attribute_string_to_value (type,
978                                               "Error: Referenced Claim Name not Found",
979                                               (void **) &data,
980                                               &data_size);
981     attr = GNUNET_RECLAIM_attribute_new (claim, &attest->id,
982                                          type, data, data_size);
983     attr->id = attest->id;
984     attr->flag = 1;
985   }
986   else
987   {
988     attr = GNUNET_RECLAIM_attribute_new (claim, &attest->id,
989                                          type, data, data_size);
990     attr->id = attest->id;
991     attr->flag = 1;
992   }
993   return attr;
994 }
995
996
997 /**
998  * Collect all attributes for an ego
999  *
1000  */
1001 static void
1002 attr_collect (void *cls,
1003               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1004               const struct GNUNET_RECLAIM_Attribute *attr)
1005 {
1006   struct RequestHandle *handle = cls;
1007   json_t *attr_obj;
1008   const char *type;
1009   char *id_str;
1010
1011   char *tmp_value;
1012   tmp_value = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
1013                                                         attr->data,
1014                                                         attr->data_size);
1015   attr_obj = json_object ();
1016   json_object_set_new (attr_obj, "value", json_string (tmp_value));
1017   json_object_set_new (attr_obj, "name", json_string (attr->name));
1018
1019   json_object_set_new (attr_obj, "flag", json_string ("1"));
1020   type = GNUNET_RECLAIM_attribute_number_to_typename (attr->type);
1021   json_object_set_new (attr_obj, "type", json_string (type));
1022   id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id,
1023                                                 sizeof(attr->id));
1024   json_object_set_new (attr_obj, "id", json_string (id_str));
1025   id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->attestation,
1026                                                 sizeof(attr->attestation));
1027   json_object_set_new (attr_obj, "attestation", json_string (id_str));
1028   json_array_append (handle->resp_object, attr_obj);
1029   json_decref (attr_obj);
1030   GNUNET_free (tmp_value);
1031 }
1032
1033
1034 /**
1035  * List attributes for identity request
1036  *
1037  * @param con_handle the connection handle
1038  * @param url the url
1039  * @param cls the RequestHandle
1040  */
1041 static void
1042 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1043                      const char *url,
1044                      void *cls)
1045 {
1046   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1047   struct RequestHandle *handle = cls;
1048   struct EgoEntry *ego_entry;
1049   char *identity;
1050
1051   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1052               "Getting attributes for %s.\n",
1053               handle->url);
1054   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1055   {
1056     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1057     GNUNET_SCHEDULER_add_now (&do_error, handle);
1058     return;
1059   }
1060   identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
1061
1062   for (ego_entry = handle->ego_head; NULL != ego_entry;
1063        ego_entry = ego_entry->next)
1064     if (0 == strcmp (identity, ego_entry->identifier))
1065       break;
1066   handle->resp_object = json_array ();
1067
1068
1069   if (NULL == ego_entry)
1070   {
1071     // Done
1072     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1073     GNUNET_SCHEDULER_add_now (&return_response, handle);
1074     return;
1075   }
1076   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1077   handle->idp = GNUNET_RECLAIM_connect (cfg);
1078   handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
1079                                                          priv_key,
1080                                                          &collect_error_cb,
1081                                                          handle,
1082                                                          &attr_collect,
1083                                                          handle,
1084                                                          &collect_finished_cb,
1085                                                          handle);
1086 }
1087
1088
1089 /**
1090  * List attributes for identity request
1091  *
1092  * @param con_handle the connection handle
1093  * @param url the url
1094  * @param cls the RequestHandle
1095  */
1096 static void
1097 delete_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1098                        const char *url,
1099                        void *cls)
1100 {
1101   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1102   struct RequestHandle *handle = cls;
1103   struct GNUNET_RECLAIM_Attribute attr;
1104   struct EgoEntry *ego_entry;
1105   char *identity_id_str;
1106   char *identity;
1107   char *id;
1108
1109   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attributes.\n");
1110   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1111   {
1112     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1113     GNUNET_SCHEDULER_add_now (&do_error, handle);
1114     return;
1115   }
1116   identity_id_str =
1117     strdup (handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1);
1118   identity = strtok (identity_id_str, "/");
1119   id = strtok (NULL, "/");
1120   if ((NULL == identity) || (NULL == id))
1121   {
1122     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
1123     GNUNET_free (identity_id_str);
1124     GNUNET_SCHEDULER_add_now (&do_error, handle);
1125     return;
1126   }
1127
1128   for (ego_entry = handle->ego_head; NULL != ego_entry;
1129        ego_entry = ego_entry->next)
1130     if (0 == strcmp (identity, ego_entry->identifier))
1131       break;
1132   handle->resp_object = json_array ();
1133   if (NULL == ego_entry)
1134   {
1135     // Done
1136     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1137     GNUNET_free (identity_id_str);
1138     GNUNET_SCHEDULER_add_now (&return_response, handle);
1139     return;
1140   }
1141   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1142   handle->idp = GNUNET_RECLAIM_connect (cfg);
1143   memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Attribute));
1144   GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
1145   attr.name = "";
1146   handle->idp_op = GNUNET_RECLAIM_attribute_delete (handle->idp,
1147                                                     priv_key,
1148                                                     &attr,
1149                                                     &delete_finished_cb,
1150                                                     handle);
1151   GNUNET_free (identity_id_str);
1152 }
1153
1154
1155 static void
1156 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1157                     const char *url,
1158                     void *cls)
1159 {
1160   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1161   struct RequestHandle *handle = cls;
1162   struct EgoEntry *ego_entry;
1163   struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1164   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1165   char term_data[handle->rest_handle->data_size + 1];
1166   json_t *data_json;
1167   json_error_t err;
1168   struct GNUNET_JSON_Specification tktspec[] =
1169   { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1170
1171   if (0 >= handle->rest_handle->data_size)
1172   {
1173     GNUNET_SCHEDULER_add_now (&do_error, handle);
1174     return;
1175   }
1176
1177   term_data[handle->rest_handle->data_size] = '\0';
1178   GNUNET_memcpy (term_data,
1179                  handle->rest_handle->data,
1180                  handle->rest_handle->data_size);
1181   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1182   if ((NULL == data_json) ||
1183       (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)))
1184   {
1185     handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1186     GNUNET_SCHEDULER_add_now (&do_error, handle);
1187     GNUNET_JSON_parse_free (tktspec);
1188     if (NULL != data_json)
1189       json_decref (data_json);
1190     return;
1191   }
1192   json_decref (data_json);
1193   if (NULL == ticket)
1194   {
1195     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1196                 "Unable to parse ticket from %s\n",
1197                 term_data);
1198     GNUNET_SCHEDULER_add_now (&do_error, handle);
1199     return;
1200   }
1201
1202   for (ego_entry = handle->ego_head; NULL != ego_entry;
1203        ego_entry = ego_entry->next)
1204   {
1205     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1206     if (0 == memcmp (&ticket->identity,
1207                      &tmp_pk,
1208                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1209       break;
1210   }
1211   if (NULL == ego_entry)
1212   {
1213     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1214     GNUNET_JSON_parse_free (tktspec);
1215     return;
1216   }
1217   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1218
1219   handle->idp = GNUNET_RECLAIM_connect (cfg);
1220   handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
1221                                                  identity_priv,
1222                                                  ticket,
1223                                                  &finished_cont,
1224                                                  handle);
1225   GNUNET_JSON_parse_free (tktspec);
1226 }
1227
1228
1229 static void
1230 consume_cont (void *cls,
1231               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1232               const struct GNUNET_RECLAIM_Attribute *attr,
1233               const struct GNUNET_RECLAIM_Attestation *attest)
1234 {
1235   struct RequestHandle *handle = cls;
1236   char *val_str;
1237   json_t *value;
1238
1239   if (NULL == identity)
1240   {
1241     GNUNET_SCHEDULER_add_now (&return_response, handle);
1242     return;
1243   }
1244
1245   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
1246   val_str = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
1247                                                       attr->data,
1248                                                       attr->data_size);
1249   if (NULL == val_str)
1250   {
1251     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1252                 "Failed to parse value for: %s\n",
1253                 attr->name);
1254     return;
1255   }
1256   value = json_string (val_str);
1257   json_object_set_new (handle->resp_object, attr->name, value);
1258   json_decref (value);
1259   GNUNET_free (val_str);
1260 }
1261
1262
1263 static void
1264 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1265                      const char *url,
1266                      void *cls)
1267 {
1268   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1269   struct RequestHandle *handle = cls;
1270   struct EgoEntry *ego_entry;
1271   struct GNUNET_RECLAIM_Ticket *ticket;
1272   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1273   char term_data[handle->rest_handle->data_size + 1];
1274   json_t *data_json;
1275   json_error_t err;
1276   struct GNUNET_JSON_Specification tktspec[] =
1277   { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1278
1279   if (0 >= handle->rest_handle->data_size)
1280   {
1281     GNUNET_SCHEDULER_add_now (&do_error, handle);
1282     return;
1283   }
1284
1285   term_data[handle->rest_handle->data_size] = '\0';
1286   GNUNET_memcpy (term_data,
1287                  handle->rest_handle->data,
1288                  handle->rest_handle->data_size);
1289   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1290   if (NULL == data_json)
1291   {
1292     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1293                 "Unable to parse JSON Object from %s\n",
1294                 term_data);
1295     GNUNET_SCHEDULER_add_now (&do_error, handle);
1296     return;
1297   }
1298   if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL))
1299   {
1300     handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1301     GNUNET_SCHEDULER_add_now (&do_error, handle);
1302     GNUNET_JSON_parse_free (tktspec);
1303     json_decref (data_json);
1304     return;
1305   }
1306   for (ego_entry = handle->ego_head; NULL != ego_entry;
1307        ego_entry = ego_entry->next)
1308   {
1309     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1310     if (0 == memcmp (&ticket->audience,
1311                      &tmp_pk,
1312                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1313       break;
1314   }
1315   if (NULL == ego_entry)
1316   {
1317     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1318     GNUNET_JSON_parse_free (tktspec);
1319     return;
1320   }
1321   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1322   handle->resp_object = json_object ();
1323   handle->idp = GNUNET_RECLAIM_connect (cfg);
1324   handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
1325                                                   identity_priv,
1326                                                   ticket,
1327                                                   &consume_cont,
1328                                                   handle);
1329   GNUNET_JSON_parse_free (tktspec);
1330 }
1331
1332
1333 /**
1334  * Respond to OPTIONS request
1335  *
1336  * @param con_handle the connection handle
1337  * @param url the url
1338  * @param cls the RequestHandle
1339  */
1340 static void
1341 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1342               const char *url,
1343               void *cls)
1344 {
1345   struct MHD_Response *resp;
1346   struct RequestHandle *handle = cls;
1347
1348   // For now, independent of path return all options
1349   resp = GNUNET_REST_create_response (NULL);
1350   MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
1351   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1352   cleanup_handle (handle);
1353   return;
1354 }
1355
1356
1357 /**
1358  * Handle rest request
1359  *
1360  * @param handle the request handle
1361  */
1362 static void
1363 init_cont (struct RequestHandle *handle)
1364 {
1365   struct GNUNET_REST_RequestHandlerError err;
1366   static const struct GNUNET_REST_RequestHandler handlers[] =
1367   { { MHD_HTTP_METHOD_GET,
1368       GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1369       &list_attribute_cont },
1370     { MHD_HTTP_METHOD_POST,
1371       GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1372       &add_attribute_cont },
1373     { MHD_HTTP_METHOD_DELETE,
1374       GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1375       &delete_attribute_cont },
1376     { MHD_HTTP_METHOD_GET,
1377       GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1378       &list_attestation_cont },
1379     { MHD_HTTP_METHOD_POST,
1380       GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1381       &add_attestation_cont },
1382     { MHD_HTTP_METHOD_DELETE,
1383       GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1384       &delete_attestation_cont },
1385     { MHD_HTTP_METHOD_GET,
1386       GNUNET_REST_API_NS_IDENTITY_TICKETS,
1387       &list_tickets_cont },
1388     { MHD_HTTP_METHOD_POST,
1389       GNUNET_REST_API_NS_IDENTITY_REVOKE,
1390       &revoke_ticket_cont },
1391     { MHD_HTTP_METHOD_POST,
1392       GNUNET_REST_API_NS_IDENTITY_CONSUME,
1393       &consume_ticket_cont },
1394     { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, &options_cont },
1395     GNUNET_REST_HANDLER_END };
1396
1397   if (GNUNET_NO ==
1398       GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1399   {
1400     handle->response_code = err.error_code;
1401     GNUNET_SCHEDULER_add_now (&do_error, handle);
1402   }
1403 }
1404
1405
1406 /**
1407  * If listing is enabled, prints information about the egos.
1408  *
1409  * This function is initially called for all egos and then again
1410  * whenever a ego's identifier changes or if it is deleted.  At the
1411  * end of the initial pass over all egos, the function is once called
1412  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1413  * be invoked in the future or that there was an error.
1414  *
1415  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1416  * this function is only called ONCE, and 'NULL' being passed in
1417  * 'ego' does indicate an error (i.e. name is taken or no default
1418  * value is known).  If 'ego' is non-NULL and if '*ctx'
1419  * is set in those callbacks, the value WILL be passed to a subsequent
1420  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1421  * that one was not NULL).
1422  *
1423  * When an identity is renamed, this function is called with the
1424  * (known) ego but the NEW identifier.
1425  *
1426  * When an identity is deleted, this function is called with the
1427  * (known) ego and "NULL" for the 'identifier'.  In this case,
1428  * the 'ego' is henceforth invalid (and the 'ctx' should also be
1429  * cleaned up).
1430  *
1431  * @param cls closure
1432  * @param ego ego handle
1433  * @param ctx context for application to store data for this ego
1434  *                 (during the lifetime of this process, initially NULL)
1435  * @param identifier identifier assigned by the user for this ego,
1436  *                   NULL if the user just deleted the ego and it
1437  *                   must thus no longer be used
1438  */
1439 static void
1440 list_ego (void *cls,
1441           struct GNUNET_IDENTITY_Ego *ego,
1442           void **ctx,
1443           const char *identifier)
1444 {
1445   struct RequestHandle *handle = cls;
1446   struct EgoEntry *ego_entry;
1447   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1448
1449   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1450   {
1451     handle->state = ID_REST_STATE_POST_INIT;
1452     init_cont (handle);
1453     return;
1454   }
1455   if (ID_REST_STATE_INIT == handle->state)
1456   {
1457     ego_entry = GNUNET_new (struct EgoEntry);
1458     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1459     ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1460     ego_entry->ego = ego;
1461     ego_entry->identifier = GNUNET_strdup (identifier);
1462     GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
1463                                       handle->ego_tail,
1464                                       ego_entry);
1465   }
1466 }
1467
1468
1469 static void
1470 rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1471                                GNUNET_REST_ResultProcessor proc,
1472                                void *proc_cls)
1473 {
1474   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1475
1476   handle->response_code = 0;
1477   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1478   handle->proc_cls = proc_cls;
1479   handle->proc = proc;
1480   handle->state = ID_REST_STATE_INIT;
1481   handle->rest_handle = rest_handle;
1482
1483   handle->url = GNUNET_strdup (rest_handle->url);
1484   if (handle->url[strlen (handle->url) - 1] == '/')
1485     handle->url[strlen (handle->url) - 1] = '\0';
1486   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1487   handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
1488   handle->timeout_task =
1489     GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
1490   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1491 }
1492
1493
1494 /**
1495  * Entry point for the plugin.
1496  *
1497  * @param cls Config info
1498  * @return NULL on error, otherwise the plugin context
1499  */
1500 void *
1501 libgnunet_plugin_rest_reclaim_init (void *cls)
1502 {
1503   static struct Plugin plugin;
1504   struct GNUNET_REST_Plugin *api;
1505
1506   cfg = cls;
1507   if (NULL != plugin.cfg)
1508     return NULL; /* can only initialize once! */
1509   memset (&plugin, 0, sizeof(struct Plugin));
1510   plugin.cfg = cfg;
1511   api = GNUNET_new (struct GNUNET_REST_Plugin);
1512   api->cls = &plugin;
1513   api->name = GNUNET_REST_API_NS_RECLAIM;
1514   api->process_request = &rest_identity_process_request;
1515   GNUNET_asprintf (&allow_methods,
1516                    "%s, %s, %s, %s, %s",
1517                    MHD_HTTP_METHOD_GET,
1518                    MHD_HTTP_METHOD_POST,
1519                    MHD_HTTP_METHOD_PUT,
1520                    MHD_HTTP_METHOD_DELETE,
1521                    MHD_HTTP_METHOD_OPTIONS);
1522
1523   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1524               _ ("Identity Provider REST API initialized\n"));
1525   return api;
1526 }
1527
1528
1529 /**
1530  * Exit point from the plugin.
1531  *
1532  * @param cls the plugin context (as returned by "init")
1533  * @return always NULL
1534  */
1535 void *
1536 libgnunet_plugin_rest_reclaim_done (void *cls)
1537 {
1538   struct GNUNET_REST_Plugin *api = cls;
1539   struct Plugin *plugin = api->cls;
1540
1541   plugin->cfg = NULL;
1542
1543   GNUNET_free_non_null (allow_methods);
1544   GNUNET_free (api);
1545   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1546               "Identity Provider REST plugin is finished\n");
1547   return NULL;
1548 }
1549
1550
1551 /* end of plugin_rest_reclaim.c */