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