towards better API
[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                 const struct GNUNET_RECLAIM_AttributeList *attrs)
624 {
625   struct RequestHandle *handle = cls;
626   json_t *attr_obj;
627   const char *type;
628   char *tmp_value;
629   char *id_str;
630
631
632   if (NULL == attest)
633   {
634     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
635                 "Attestation Collection with empty Attestation\n");
636     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
637     return;
638   }
639
640   if ((NULL == attest->name) || (NULL == attest->data))
641   {
642     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
643                 "Attestation Collection with empty Name/Value\n");
644     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
645     return;
646   }
647
648   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attestation: %s\n",
649               attest->name);
650
651   tmp_value = GNUNET_RECLAIM_attestation_value_to_string (attest->type,
652                                                           attest->data,
653                                                           attest->data_size);
654   attr_obj = json_object ();
655   json_object_set_new (attr_obj, "value", json_string (tmp_value));
656   json_object_set_new (attr_obj, "name", json_string (attest->name));
657   type = GNUNET_RECLAIM_attestation_number_to_typename (attest->type);
658   json_object_set_new (attr_obj, "type", json_string (type));
659   id_str = GNUNET_STRINGS_data_to_string_alloc (&attest->id,
660                                                 sizeof(attest->id));
661   json_object_set_new (attr_obj, "id", json_string (id_str));
662   json_array_append (handle->resp_object, attr_obj);
663   json_decref (attr_obj);
664   GNUNET_free (tmp_value);
665   GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
666 }
667
668
669 /**
670  * Lists attestation for identity request
671  *
672  * @param con_handle the connection handle
673  * @param url the url
674  * @param cls the RequestHandle
675  */
676 static void
677 list_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
678                        const char *url,
679                        void *cls)
680 {
681   struct RequestHandle *handle = cls;
682   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
683   struct EgoEntry *ego_entry;
684   char *identity;
685
686   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
687               "Getting attestations for %s.\n",
688               handle->url);
689   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
690         handle->url))
691   {
692     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
693     GNUNET_SCHEDULER_add_now (&do_error, handle);
694     return;
695   }
696   identity = handle->url + strlen (
697     GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1;
698
699   for (ego_entry = handle->ego_head; NULL != ego_entry;
700        ego_entry = ego_entry->next)
701     if (0 == strcmp (identity, ego_entry->identifier))
702       break;
703   handle->resp_object = json_array ();
704
705
706   if (NULL == ego_entry)
707   {
708     // Done
709     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
710     GNUNET_SCHEDULER_add_now (&return_response, handle);
711     return;
712   }
713   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
714   handle->idp = GNUNET_RECLAIM_connect (cfg);
715   handle->attest_it = GNUNET_RECLAIM_get_attestations_start (handle->idp,
716                                                              priv_key,
717                                                              &collect_error_cb,
718                                                              handle,
719                                                              &attest_collect,
720                                                              handle,
721                                                              &
722                                                              collect_finished_cb,
723                                                              handle);
724 }
725
726
727 /**
728  * Deletes attestation from an identity
729  *
730  * @param con_handle the connection handle
731  * @param url the url
732  * @param cls the RequestHandle
733  */
734 static void
735 delete_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
736                          const char *url,
737                          void *cls)
738 {
739   struct RequestHandle *handle = cls;
740   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
741   struct GNUNET_RECLAIM_Attestation attr;
742   struct EgoEntry *ego_entry;
743   char *identity_id_str;
744   char *identity;
745   char *id;
746
747   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attestation.\n");
748   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
749         handle->url))
750   {
751     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
752     GNUNET_SCHEDULER_add_now (&do_error, handle);
753     return;
754   }
755   identity_id_str =
756     strdup (handle->url + strlen (
757               GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1);
758   identity = strtok (identity_id_str, "/");
759   id = strtok (NULL, "/");
760   if ((NULL == identity) || (NULL == id))
761   {
762     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
763     GNUNET_free (identity_id_str);
764     GNUNET_SCHEDULER_add_now (&do_error, handle);
765     return;
766   }
767
768   for (ego_entry = handle->ego_head; NULL != ego_entry;
769        ego_entry = ego_entry->next)
770     if (0 == strcmp (identity, ego_entry->identifier))
771       break;
772   handle->resp_object = json_array ();
773   if (NULL == ego_entry)
774   {
775     // Done
776     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
777     GNUNET_free (identity_id_str);
778     GNUNET_SCHEDULER_add_now (&return_response, handle);
779     return;
780   }
781   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
782   handle->idp = GNUNET_RECLAIM_connect (cfg);
783   memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Attestation));
784   GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
785   attr.name = "";
786   handle->idp_op = GNUNET_RECLAIM_attestation_delete (handle->idp,
787                                                       priv_key,
788                                                       &attr,
789                                                       &delete_finished_cb,
790                                                       handle);
791   GNUNET_free (identity_id_str);
792 }
793
794
795 /**
796  * List tickets for identity request
797  *
798  * @param con_handle the connection handle
799  * @param url the url
800  * @param cls the RequestHandle
801  */
802 static void
803 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
804                    const char *url,
805                    void *cls)
806 {
807   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
808   struct RequestHandle *handle = cls;
809   struct EgoEntry *ego_entry;
810   char *identity;
811
812   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
813               "Getting tickets for %s.\n",
814               handle->url);
815   if (strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= strlen (handle->url))
816   {
817     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
818     GNUNET_SCHEDULER_add_now (&do_error, handle);
819     return;
820   }
821   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
822
823   for (ego_entry = handle->ego_head; NULL != ego_entry;
824        ego_entry = ego_entry->next)
825     if (0 == strcmp (identity, ego_entry->identifier))
826       break;
827   handle->resp_object = json_array ();
828
829   if (NULL == ego_entry)
830   {
831     // Done
832     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
833     GNUNET_SCHEDULER_add_now (&return_response, handle);
834     return;
835   }
836   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
837   handle->idp = GNUNET_RECLAIM_connect (cfg);
838   handle->ticket_it =
839     GNUNET_RECLAIM_ticket_iteration_start (handle->idp,
840                                            priv_key,
841                                            &collect_error_cb,
842                                            handle,
843                                            &ticket_collect,
844                                            handle,
845                                            &collect_finished_cb,
846                                            handle);
847 }
848
849
850 static void
851 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
852                     const char *url,
853                     void *cls)
854 {
855   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
856   const char *identity;
857   struct RequestHandle *handle = cls;
858   struct EgoEntry *ego_entry;
859   struct GNUNET_RECLAIM_Attribute *attribute;
860   struct GNUNET_TIME_Relative exp;
861   char term_data[handle->rest_handle->data_size + 1];
862   json_t *data_json;
863   json_error_t err;
864   struct GNUNET_JSON_Specification attrspec[] =
865   { GNUNET_RECLAIM_JSON_spec_claim (&attribute), GNUNET_JSON_spec_end () };
866
867   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
868               "Adding an attribute for %s.\n",
869               handle->url);
870   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
871   {
872     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
873     GNUNET_SCHEDULER_add_now (&do_error, handle);
874     return;
875   }
876   identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
877
878   for (ego_entry = handle->ego_head; NULL != ego_entry;
879        ego_entry = ego_entry->next)
880     if (0 == strcmp (identity, ego_entry->identifier))
881       break;
882
883   if (NULL == ego_entry)
884   {
885     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
886     return;
887   }
888   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
889
890   if (0 >= handle->rest_handle->data_size)
891   {
892     GNUNET_SCHEDULER_add_now (&do_error, handle);
893     return;
894   }
895
896   term_data[handle->rest_handle->data_size] = '\0';
897   GNUNET_memcpy (term_data,
898                  handle->rest_handle->data,
899                  handle->rest_handle->data_size);
900   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
901   GNUNET_assert (GNUNET_OK ==
902                  GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
903   json_decref (data_json);
904   if (NULL == attribute)
905   {
906     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
907                 "Unable to parse attribute from %s\n",
908                 term_data);
909     GNUNET_SCHEDULER_add_now (&do_error, handle);
910     return;
911   }
912   /**
913    * New ID for attribute
914    */
915   if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id))
916     GNUNET_RECLAIM_id_generate (&attribute->id);
917   handle->idp = GNUNET_RECLAIM_connect (cfg);
918   exp = GNUNET_TIME_UNIT_HOURS;
919   handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
920                                                    identity_priv,
921                                                    attribute,
922                                                    &exp,
923                                                    &finished_cont,
924                                                    handle);
925   GNUNET_JSON_parse_free (attrspec);
926 }
927
928
929 /**
930  * Parse a JWT and return the respective claim value as Attribute
931  *
932  * @param attest the jwt attestation
933  * @param claim the name of the claim in the JWT
934  *
935  * @return a GNUNET_RECLAIM_Attribute, containing the new value
936  */
937 struct GNUNET_RECLAIM_Attribute *
938 parse_jwt (const struct GNUNET_RECLAIM_Attestation *attest,
939            const char *claim)
940 {
941   char *jwt_string;
942   struct GNUNET_RECLAIM_Attribute *attr;
943   char delim[] = ".";
944   const char *type_str = NULL;
945   const char *val_str = NULL;
946   char *data;
947   size_t data_size;
948   uint32_t type;
949   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing JWT attributes.\n");
950   char *decoded_jwt;
951   json_t *json_val;
952   json_error_t *json_err = NULL;
953
954   jwt_string = GNUNET_RECLAIM_attestation_value_to_string (attest->type,
955                                                            attest->data,
956                                                            attest->data_size);
957   char *jwt_body = strtok (jwt_string, delim);
958   jwt_body = strtok (NULL, delim);
959   GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body),
960                                 (void **) &decoded_jwt);
961   json_val = json_loads (decoded_jwt, JSON_DECODE_ANY, json_err);
962   const char *key;
963   json_t *value;
964   json_object_foreach (json_val, key, value) {
965     if (0 == strcasecmp (key,claim))
966     {
967       val_str = json_dumps (value, JSON_ENCODE_ANY);
968     }
969   }
970   type_str = "String";
971   type = GNUNET_RECLAIM_attribute_typename_to_number (type_str);
972   if (GNUNET_SYSERR == GNUNET_RECLAIM_attribute_string_to_value (type,val_str,
973                                                                  (void **) &data,
974                                                                  &data_size))
975   {
976     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
977                 "Attribute value from JWT Parser invalid!\n");
978     GNUNET_RECLAIM_attribute_string_to_value (type,
979                                               "Error: Referenced Claim Name not Found",
980                                               (void **) &data,
981                                               &data_size);
982     attr = GNUNET_RECLAIM_attribute_new (claim, &attest->id,
983                                          type, data, data_size);
984     attr->id = attest->id;
985     attr->flag = 1;
986   }
987   else
988   {
989     attr = GNUNET_RECLAIM_attribute_new (claim, &attest->id,
990                                          type, data, data_size);
991     attr->id = attest->id;
992     attr->flag = 1;
993   }
994   return attr;
995 }
996
997
998 /**
999  * Collect all attributes for an ego
1000  *
1001  */
1002 static void
1003 attr_collect (void *cls,
1004               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1005               const struct GNUNET_RECLAIM_Attribute *attr)
1006 {
1007   struct RequestHandle *handle = cls;
1008   json_t *attr_obj;
1009   const char *type;
1010   char *id_str;
1011
1012   char *tmp_value;
1013   tmp_value = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
1014                                                         attr->data,
1015                                                         attr->data_size);
1016   attr_obj = json_object ();
1017   json_object_set_new (attr_obj, "value", json_string (tmp_value));
1018   json_object_set_new (attr_obj, "name", json_string (attr->name));
1019
1020   json_object_set_new (attr_obj, "flag", json_string ("1"));
1021   type = GNUNET_RECLAIM_attribute_number_to_typename (attr->type);
1022   json_object_set_new (attr_obj, "type", json_string (type));
1023   id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id,
1024                                                 sizeof(attr->id));
1025   json_object_set_new (attr_obj, "id", json_string (id_str));
1026   id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->attestation,
1027                                                 sizeof(attr->attestation));
1028   json_object_set_new (attr_obj, "attestation", json_string (id_str));
1029   json_array_append (handle->resp_object, attr_obj);
1030   json_decref (attr_obj);
1031   GNUNET_free (tmp_value);
1032 }
1033
1034
1035 /**
1036  * List attributes for identity request
1037  *
1038  * @param con_handle the connection handle
1039  * @param url the url
1040  * @param cls the RequestHandle
1041  */
1042 static void
1043 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1044                      const char *url,
1045                      void *cls)
1046 {
1047   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1048   struct RequestHandle *handle = cls;
1049   struct EgoEntry *ego_entry;
1050   char *identity;
1051
1052   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1053               "Getting attributes for %s.\n",
1054               handle->url);
1055   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1056   {
1057     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1058     GNUNET_SCHEDULER_add_now (&do_error, handle);
1059     return;
1060   }
1061   identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
1062
1063   for (ego_entry = handle->ego_head; NULL != ego_entry;
1064        ego_entry = ego_entry->next)
1065     if (0 == strcmp (identity, ego_entry->identifier))
1066       break;
1067   handle->resp_object = json_array ();
1068
1069
1070   if (NULL == ego_entry)
1071   {
1072     // Done
1073     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1074     GNUNET_SCHEDULER_add_now (&return_response, handle);
1075     return;
1076   }
1077   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1078   handle->idp = GNUNET_RECLAIM_connect (cfg);
1079   handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
1080                                                          priv_key,
1081                                                          &collect_error_cb,
1082                                                          handle,
1083                                                          &attr_collect,
1084                                                          handle,
1085                                                          &collect_finished_cb,
1086                                                          handle);
1087 }
1088
1089
1090 /**
1091  * List attributes for identity request
1092  *
1093  * @param con_handle the connection handle
1094  * @param url the url
1095  * @param cls the RequestHandle
1096  */
1097 static void
1098 delete_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1099                        const char *url,
1100                        void *cls)
1101 {
1102   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1103   struct RequestHandle *handle = cls;
1104   struct GNUNET_RECLAIM_Attribute attr;
1105   struct EgoEntry *ego_entry;
1106   char *identity_id_str;
1107   char *identity;
1108   char *id;
1109
1110   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attributes.\n");
1111   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1112   {
1113     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1114     GNUNET_SCHEDULER_add_now (&do_error, handle);
1115     return;
1116   }
1117   identity_id_str =
1118     strdup (handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1);
1119   identity = strtok (identity_id_str, "/");
1120   id = strtok (NULL, "/");
1121   if ((NULL == identity) || (NULL == id))
1122   {
1123     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
1124     GNUNET_free (identity_id_str);
1125     GNUNET_SCHEDULER_add_now (&do_error, handle);
1126     return;
1127   }
1128
1129   for (ego_entry = handle->ego_head; NULL != ego_entry;
1130        ego_entry = ego_entry->next)
1131     if (0 == strcmp (identity, ego_entry->identifier))
1132       break;
1133   handle->resp_object = json_array ();
1134   if (NULL == ego_entry)
1135   {
1136     // Done
1137     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1138     GNUNET_free (identity_id_str);
1139     GNUNET_SCHEDULER_add_now (&return_response, handle);
1140     return;
1141   }
1142   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1143   handle->idp = GNUNET_RECLAIM_connect (cfg);
1144   memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Attribute));
1145   GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
1146   attr.name = "";
1147   handle->idp_op = GNUNET_RECLAIM_attribute_delete (handle->idp,
1148                                                     priv_key,
1149                                                     &attr,
1150                                                     &delete_finished_cb,
1151                                                     handle);
1152   GNUNET_free (identity_id_str);
1153 }
1154
1155
1156 static void
1157 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1158                     const char *url,
1159                     void *cls)
1160 {
1161   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1162   struct RequestHandle *handle = cls;
1163   struct EgoEntry *ego_entry;
1164   struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1165   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1166   char term_data[handle->rest_handle->data_size + 1];
1167   json_t *data_json;
1168   json_error_t err;
1169   struct GNUNET_JSON_Specification tktspec[] =
1170   { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1171
1172   if (0 >= handle->rest_handle->data_size)
1173   {
1174     GNUNET_SCHEDULER_add_now (&do_error, handle);
1175     return;
1176   }
1177
1178   term_data[handle->rest_handle->data_size] = '\0';
1179   GNUNET_memcpy (term_data,
1180                  handle->rest_handle->data,
1181                  handle->rest_handle->data_size);
1182   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1183   if ((NULL == data_json) ||
1184       (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)))
1185   {
1186     handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1187     GNUNET_SCHEDULER_add_now (&do_error, handle);
1188     GNUNET_JSON_parse_free (tktspec);
1189     if (NULL != data_json)
1190       json_decref (data_json);
1191     return;
1192   }
1193   json_decref (data_json);
1194   if (NULL == ticket)
1195   {
1196     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1197                 "Unable to parse ticket from %s\n",
1198                 term_data);
1199     GNUNET_SCHEDULER_add_now (&do_error, handle);
1200     return;
1201   }
1202
1203   for (ego_entry = handle->ego_head; NULL != ego_entry;
1204        ego_entry = ego_entry->next)
1205   {
1206     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1207     if (0 == memcmp (&ticket->identity,
1208                      &tmp_pk,
1209                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1210       break;
1211   }
1212   if (NULL == ego_entry)
1213   {
1214     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1215     GNUNET_JSON_parse_free (tktspec);
1216     return;
1217   }
1218   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1219
1220   handle->idp = GNUNET_RECLAIM_connect (cfg);
1221   handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
1222                                                  identity_priv,
1223                                                  ticket,
1224                                                  &finished_cont,
1225                                                  handle);
1226   GNUNET_JSON_parse_free (tktspec);
1227 }
1228
1229
1230 static void
1231 consume_cont (void *cls,
1232               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1233               const struct GNUNET_RECLAIM_Attribute *attr,
1234               const struct GNUNET_RECLAIM_Attestation *attest)
1235 {
1236   struct RequestHandle *handle = cls;
1237   char *val_str;
1238   json_t *value;
1239
1240   if (NULL == identity)
1241   {
1242     GNUNET_SCHEDULER_add_now (&return_response, handle);
1243     return;
1244   }
1245
1246   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
1247   val_str = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
1248                                                       attr->data,
1249                                                       attr->data_size);
1250   if (NULL == val_str)
1251   {
1252     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1253                 "Failed to parse value for: %s\n",
1254                 attr->name);
1255     return;
1256   }
1257   value = json_string (val_str);
1258   json_object_set_new (handle->resp_object, attr->name, value);
1259   json_decref (value);
1260   GNUNET_free (val_str);
1261 }
1262
1263
1264 static void
1265 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1266                      const char *url,
1267                      void *cls)
1268 {
1269   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1270   struct RequestHandle *handle = cls;
1271   struct EgoEntry *ego_entry;
1272   struct GNUNET_RECLAIM_Ticket *ticket;
1273   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1274   char term_data[handle->rest_handle->data_size + 1];
1275   json_t *data_json;
1276   json_error_t err;
1277   struct GNUNET_JSON_Specification tktspec[] =
1278   { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1279
1280   if (0 >= handle->rest_handle->data_size)
1281   {
1282     GNUNET_SCHEDULER_add_now (&do_error, handle);
1283     return;
1284   }
1285
1286   term_data[handle->rest_handle->data_size] = '\0';
1287   GNUNET_memcpy (term_data,
1288                  handle->rest_handle->data,
1289                  handle->rest_handle->data_size);
1290   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1291   if (NULL == data_json)
1292   {
1293     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1294                 "Unable to parse JSON Object from %s\n",
1295                 term_data);
1296     GNUNET_SCHEDULER_add_now (&do_error, handle);
1297     return;
1298   }
1299   if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL))
1300   {
1301     handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1302     GNUNET_SCHEDULER_add_now (&do_error, handle);
1303     GNUNET_JSON_parse_free (tktspec);
1304     json_decref (data_json);
1305     return;
1306   }
1307   for (ego_entry = handle->ego_head; NULL != ego_entry;
1308        ego_entry = ego_entry->next)
1309   {
1310     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1311     if (0 == memcmp (&ticket->audience,
1312                      &tmp_pk,
1313                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1314       break;
1315   }
1316   if (NULL == ego_entry)
1317   {
1318     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1319     GNUNET_JSON_parse_free (tktspec);
1320     return;
1321   }
1322   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1323   handle->resp_object = json_object ();
1324   handle->idp = GNUNET_RECLAIM_connect (cfg);
1325   handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
1326                                                   identity_priv,
1327                                                   ticket,
1328                                                   &consume_cont,
1329                                                   handle);
1330   GNUNET_JSON_parse_free (tktspec);
1331 }
1332
1333
1334 /**
1335  * Respond to OPTIONS request
1336  *
1337  * @param con_handle the connection handle
1338  * @param url the url
1339  * @param cls the RequestHandle
1340  */
1341 static void
1342 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1343               const char *url,
1344               void *cls)
1345 {
1346   struct MHD_Response *resp;
1347   struct RequestHandle *handle = cls;
1348
1349   // For now, independent of path return all options
1350   resp = GNUNET_REST_create_response (NULL);
1351   MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
1352   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1353   cleanup_handle (handle);
1354   return;
1355 }
1356
1357
1358 /**
1359  * Handle rest request
1360  *
1361  * @param handle the request handle
1362  */
1363 static void
1364 init_cont (struct RequestHandle *handle)
1365 {
1366   struct GNUNET_REST_RequestHandlerError err;
1367   static const struct GNUNET_REST_RequestHandler handlers[] =
1368   { { MHD_HTTP_METHOD_GET,
1369       GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1370       &list_attribute_cont },
1371     { MHD_HTTP_METHOD_POST,
1372       GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1373       &add_attribute_cont },
1374     { MHD_HTTP_METHOD_DELETE,
1375       GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1376       &delete_attribute_cont },
1377     { MHD_HTTP_METHOD_GET,
1378       GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1379       &list_attestation_cont },
1380     { MHD_HTTP_METHOD_POST,
1381       GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1382       &add_attestation_cont },
1383     { MHD_HTTP_METHOD_DELETE,
1384       GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1385       &delete_attestation_cont },
1386     { MHD_HTTP_METHOD_GET,
1387       GNUNET_REST_API_NS_IDENTITY_TICKETS,
1388       &list_tickets_cont },
1389     { MHD_HTTP_METHOD_POST,
1390       GNUNET_REST_API_NS_IDENTITY_REVOKE,
1391       &revoke_ticket_cont },
1392     { MHD_HTTP_METHOD_POST,
1393       GNUNET_REST_API_NS_IDENTITY_CONSUME,
1394       &consume_ticket_cont },
1395     { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, &options_cont },
1396     GNUNET_REST_HANDLER_END };
1397
1398   if (GNUNET_NO ==
1399       GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1400   {
1401     handle->response_code = err.error_code;
1402     GNUNET_SCHEDULER_add_now (&do_error, handle);
1403   }
1404 }
1405
1406
1407 /**
1408  * If listing is enabled, prints information about the egos.
1409  *
1410  * This function is initially called for all egos and then again
1411  * whenever a ego's identifier changes or if it is deleted.  At the
1412  * end of the initial pass over all egos, the function is once called
1413  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1414  * be invoked in the future or that there was an error.
1415  *
1416  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1417  * this function is only called ONCE, and 'NULL' being passed in
1418  * 'ego' does indicate an error (i.e. name is taken or no default
1419  * value is known).  If 'ego' is non-NULL and if '*ctx'
1420  * is set in those callbacks, the value WILL be passed to a subsequent
1421  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1422  * that one was not NULL).
1423  *
1424  * When an identity is renamed, this function is called with the
1425  * (known) ego but the NEW identifier.
1426  *
1427  * When an identity is deleted, this function is called with the
1428  * (known) ego and "NULL" for the 'identifier'.  In this case,
1429  * the 'ego' is henceforth invalid (and the 'ctx' should also be
1430  * cleaned up).
1431  *
1432  * @param cls closure
1433  * @param ego ego handle
1434  * @param ctx context for application to store data for this ego
1435  *                 (during the lifetime of this process, initially NULL)
1436  * @param identifier identifier assigned by the user for this ego,
1437  *                   NULL if the user just deleted the ego and it
1438  *                   must thus no longer be used
1439  */
1440 static void
1441 list_ego (void *cls,
1442           struct GNUNET_IDENTITY_Ego *ego,
1443           void **ctx,
1444           const char *identifier)
1445 {
1446   struct RequestHandle *handle = cls;
1447   struct EgoEntry *ego_entry;
1448   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1449
1450   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1451   {
1452     handle->state = ID_REST_STATE_POST_INIT;
1453     init_cont (handle);
1454     return;
1455   }
1456   if (ID_REST_STATE_INIT == handle->state)
1457   {
1458     ego_entry = GNUNET_new (struct EgoEntry);
1459     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1460     ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1461     ego_entry->ego = ego;
1462     ego_entry->identifier = GNUNET_strdup (identifier);
1463     GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
1464                                       handle->ego_tail,
1465                                       ego_entry);
1466   }
1467 }
1468
1469
1470 static void
1471 rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1472                                GNUNET_REST_ResultProcessor proc,
1473                                void *proc_cls)
1474 {
1475   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1476
1477   handle->response_code = 0;
1478   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1479   handle->proc_cls = proc_cls;
1480   handle->proc = proc;
1481   handle->state = ID_REST_STATE_INIT;
1482   handle->rest_handle = rest_handle;
1483
1484   handle->url = GNUNET_strdup (rest_handle->url);
1485   if (handle->url[strlen (handle->url) - 1] == '/')
1486     handle->url[strlen (handle->url) - 1] = '\0';
1487   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1488   handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
1489   handle->timeout_task =
1490     GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
1491   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1492 }
1493
1494
1495 /**
1496  * Entry point for the plugin.
1497  *
1498  * @param cls Config info
1499  * @return NULL on error, otherwise the plugin context
1500  */
1501 void *
1502 libgnunet_plugin_rest_reclaim_init (void *cls)
1503 {
1504   static struct Plugin plugin;
1505   struct GNUNET_REST_Plugin *api;
1506
1507   cfg = cls;
1508   if (NULL != plugin.cfg)
1509     return NULL; /* can only initialize once! */
1510   memset (&plugin, 0, sizeof(struct Plugin));
1511   plugin.cfg = cfg;
1512   api = GNUNET_new (struct GNUNET_REST_Plugin);
1513   api->cls = &plugin;
1514   api->name = GNUNET_REST_API_NS_RECLAIM;
1515   api->process_request = &rest_identity_process_request;
1516   GNUNET_asprintf (&allow_methods,
1517                    "%s, %s, %s, %s, %s",
1518                    MHD_HTTP_METHOD_GET,
1519                    MHD_HTTP_METHOD_POST,
1520                    MHD_HTTP_METHOD_PUT,
1521                    MHD_HTTP_METHOD_DELETE,
1522                    MHD_HTTP_METHOD_OPTIONS);
1523
1524   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1525               _ ("Identity Provider REST API initialized\n"));
1526   return api;
1527 }
1528
1529
1530 /**
1531  * Exit point from the plugin.
1532  *
1533  * @param cls the plugin context (as returned by "init")
1534  * @return always NULL
1535  */
1536 void *
1537 libgnunet_plugin_rest_reclaim_done (void *cls)
1538 {
1539   struct GNUNET_REST_Plugin *api = cls;
1540   struct Plugin *plugin = api->cls;
1541
1542   plugin->cfg = NULL;
1543
1544   GNUNET_free_non_null (allow_methods);
1545   GNUNET_free (api);
1546   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1547               "Identity Provider REST plugin is finished\n");
1548   return NULL;
1549 }
1550
1551
1552 /* end of plugin_rest_reclaim.c */