move reclaim and gns back into subdirs
[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
28 #include "platform.h"
29 #include "gnunet_rest_plugin.h"
30 #include "gnunet_identity_service.h"
31 #include "gnunet_gns_service.h"
32 #include "gnunet_gnsrecord_lib.h"
33 #include "gnunet_namestore_service.h"
34 #include "gnunet_rest_lib.h"
35 #include "microhttpd.h"
36 #include <jansson.h>
37 #include <inttypes.h>
38 #include "gnunet_signatures.h"
39 #include "gnunet_reclaim_attribute_lib.h"
40 #include "gnunet_reclaim_service.h"
41 #include "json_reclaim.h"
42
43 /**
44  * REST root namespace
45  */
46 #define GNUNET_REST_API_NS_RECLAIM "/reclaim"
47
48 /**
49  * Attribute namespace
50  */
51 #define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/reclaim/attributes"
52
53 /**
54  * Ticket namespace
55  */
56 #define GNUNET_REST_API_NS_IDENTITY_TICKETS "/reclaim/tickets"
57
58 /**
59  * Revoke namespace
60  */
61 #define GNUNET_REST_API_NS_IDENTITY_REVOKE "/reclaim/revoke"
62
63 /**
64  * Revoke namespace
65  */
66 #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/reclaim/consume"
67
68 /**
69  * State while collecting all egos
70  */
71 #define ID_REST_STATE_INIT 0
72
73 /**
74  * Done collecting egos
75  */
76 #define ID_REST_STATE_POST_INIT 1
77
78 /**
79  * The configuration handle
80  */
81 const struct GNUNET_CONFIGURATION_Handle *cfg;
82
83 /**
84  * HTTP methods allows for this plugin
85  */
86 static char* allow_methods;
87
88 /**
89  * @brief struct returned by the initialization function of the plugin
90  */
91 struct Plugin
92 {
93   const struct GNUNET_CONFIGURATION_Handle *cfg;
94 };
95
96 /**
97  * The ego list
98  */
99 struct EgoEntry
100 {
101   /**
102    * DLL
103    */
104   struct EgoEntry *next;
105
106   /**
107    * DLL
108    */
109   struct EgoEntry *prev;
110
111   /**
112    * Ego Identifier
113    */
114   char *identifier;
115
116   /**
117    * Public key string
118    */
119   char *keystring;
120
121   /**
122    * The Ego
123    */
124   struct GNUNET_IDENTITY_Ego *ego;
125 };
126
127
128 struct RequestHandle
129 {
130   /**
131    * Ego list
132    */
133   struct EgoEntry *ego_head;
134
135   /**
136    * Ego list
137    */
138   struct EgoEntry *ego_tail;
139
140   /**
141    * Selected ego
142    */
143   struct EgoEntry *ego_entry;
144
145   /**
146    * Pointer to ego private key
147    */
148   struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
149
150   /**
151    * The processing state
152    */
153   int state;
154
155   /**
156    * Handle to Identity service.
157    */
158   struct GNUNET_IDENTITY_Handle *identity_handle;
159
160   /**
161    * Rest connection
162    */
163   struct GNUNET_REST_RequestHandle *rest_handle;
164
165   /**
166    * Handle to NAMESTORE
167    */
168   struct GNUNET_NAMESTORE_Handle *namestore_handle;
169
170   /**
171    * Iterator for NAMESTORE
172    */
173   struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
174
175   /**
176    * Attribute claim list
177    */
178   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list;
179
180   /**
181    * IDENTITY Operation
182    */
183   struct GNUNET_IDENTITY_Operation *op;
184
185   /**
186    * Identity Provider
187    */
188   struct GNUNET_RECLAIM_Handle *idp;
189
190   /**
191    * Idp Operation
192    */
193   struct GNUNET_RECLAIM_Operation *idp_op;
194
195   /**
196    * Attribute iterator
197    */
198   struct GNUNET_RECLAIM_AttributeIterator *attr_it;
199
200   /**
201    * Ticket iterator
202    */
203   struct GNUNET_RECLAIM_TicketIterator *ticket_it;
204
205   /**
206    * A ticket
207    */
208   struct GNUNET_RECLAIM_Ticket ticket;
209
210   /**
211    * Desired timeout for the lookup (default is no timeout).
212    */
213   struct GNUNET_TIME_Relative timeout;
214
215   /**
216    * ID of a task associated with the resolution process.
217    */
218   struct GNUNET_SCHEDULER_Task *timeout_task;
219
220   /**
221    * The plugin result processor
222    */
223   GNUNET_REST_ResultProcessor proc;
224
225   /**
226    * The closure of the result processor
227    */
228   void *proc_cls;
229
230   /**
231    * The url
232    */
233   char *url;
234
235   /**
236    * Error response message
237    */
238   char *emsg;
239
240   /**
241    * Reponse code
242    */
243   int response_code;
244
245   /**
246    * Response object
247    */
248   json_t *resp_object;
249
250 };
251
252 /**
253  * Cleanup lookup handle
254  * @param handle Handle to clean up
255  */
256 static void
257 cleanup_handle (struct RequestHandle *handle)
258 {
259   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry;
260   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp;
261   struct EgoEntry *ego_entry;
262   struct EgoEntry *ego_tmp;
263   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
264               "Cleaning up\n");
265   if (NULL != handle->resp_object)
266     json_decref (handle->resp_object);
267   if (NULL != handle->timeout_task)
268     GNUNET_SCHEDULER_cancel (handle->timeout_task);
269   if (NULL != handle->identity_handle)
270     GNUNET_IDENTITY_disconnect (handle->identity_handle);
271   if (NULL != handle->attr_it)
272     GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
273   if (NULL != handle->ticket_it)
274     GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
275   if (NULL != handle->idp)
276     GNUNET_RECLAIM_disconnect (handle->idp);
277   if (NULL != handle->url)
278     GNUNET_free (handle->url);
279   if (NULL != handle->emsg)
280     GNUNET_free (handle->emsg);
281   if (NULL != handle->namestore_handle)
282     GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
283   if ( NULL != handle->attr_list )
284   {
285     for (claim_entry = handle->attr_list->list_head;
286     NULL != claim_entry;)
287     {
288       claim_tmp = claim_entry;
289       claim_entry = claim_entry->next;
290       GNUNET_free(claim_tmp->claim);
291       GNUNET_free(claim_tmp);
292     }
293     GNUNET_free (handle->attr_list);
294   }
295   for (ego_entry = handle->ego_head;
296        NULL != ego_entry;)
297   {
298     ego_tmp = ego_entry;
299     ego_entry = ego_entry->next;
300     GNUNET_free (ego_tmp->identifier);
301     GNUNET_free (ego_tmp->keystring);
302     GNUNET_free (ego_tmp);
303   }
304   if (NULL != handle->attr_it)
305   {
306     GNUNET_free(handle->attr_it);
307   }
308   GNUNET_free (handle);
309 }
310
311 static void
312 cleanup_handle_delayed (void *cls)
313 {
314   cleanup_handle (cls);
315 }
316
317
318 /**
319  * Task run on error, sends error message.  Cleans up everything.
320  *
321  * @param cls the `struct RequestHandle`
322  */
323 static void
324 do_error (void *cls)
325 {
326   struct RequestHandle *handle = cls;
327   struct MHD_Response *resp;
328   char *json_error;
329
330   GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }",
331                    handle->emsg);
332   if ( 0 == handle->response_code )
333   {
334     handle->response_code = MHD_HTTP_BAD_REQUEST;
335   }
336   resp = GNUNET_REST_create_response (json_error);
337   MHD_add_response_header (resp, "Content-Type", "application/json");
338   handle->proc (handle->proc_cls, resp, handle->response_code);
339   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
340   GNUNET_free (json_error);
341 }
342
343
344 /**
345  * Task run on timeout, sends error message.  Cleans up everything.
346  *
347  * @param cls the `struct RequestHandle`
348  */
349 static void
350 do_timeout (void *cls)
351 {
352   struct RequestHandle *handle = cls;
353
354   handle->timeout_task = NULL;
355   do_error (handle);
356 }
357
358
359 static void
360 collect_error_cb (void *cls)
361 {
362   struct RequestHandle *handle = cls;
363
364   do_error (handle);
365 }
366
367 static void
368 finished_cont (void *cls,
369                int32_t success,
370                const char *emsg)
371 {
372   struct RequestHandle *handle = cls;
373   struct MHD_Response *resp;
374
375   resp = GNUNET_REST_create_response (emsg);
376   if (GNUNET_OK != success)
377   {
378     GNUNET_SCHEDULER_add_now (&do_error, handle);
379     return;
380   }
381   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
382   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
383 }
384
385
386 /**
387  * Return attributes for identity
388  *
389  * @param cls the request handle
390  */
391 static void
392 return_response (void *cls)
393 {
394   char* result_str;
395   struct RequestHandle *handle = cls;
396   struct MHD_Response *resp;
397
398   result_str = json_dumps (handle->resp_object, 0);
399   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
400   resp = GNUNET_REST_create_response (result_str);
401   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
402   GNUNET_free (result_str);
403   cleanup_handle (handle);
404 }
405
406 static void
407 collect_finished_cb (void *cls)
408 {
409   struct RequestHandle *handle = cls;
410   //Done
411   handle->attr_it = NULL;
412   handle->ticket_it = NULL;
413   GNUNET_SCHEDULER_add_now (&return_response, handle);
414 }
415
416
417 /**
418  * Collect all attributes for an ego
419  *
420  */
421 static void
422 ticket_collect (void *cls,
423                 const struct GNUNET_RECLAIM_Ticket *ticket)
424 {
425   json_t *json_resource;
426   struct RequestHandle *handle = cls;
427   json_t *value;
428   char* tmp;
429
430   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
431   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
432                                              sizeof (uint64_t));
433   json_resource = json_object ();
434   GNUNET_free (tmp);
435   json_array_append (handle->resp_object,
436                      json_resource);
437
438   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
439                                              sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
440   value = json_string (tmp);
441   json_object_set_new (json_resource,
442                        "issuer",
443                        value);
444   GNUNET_free (tmp);
445   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
446                                              sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
447   value = json_string (tmp);
448   json_object_set_new (json_resource,
449                        "audience",
450                        value);
451   GNUNET_free (tmp);
452   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
453                                              sizeof (uint64_t));
454   value = json_string (tmp);
455   json_object_set_new (json_resource,
456                        "rnd",
457                        value);
458   GNUNET_free (tmp);
459   GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it);
460 }
461
462
463
464 /**
465  * List tickets for identity request
466  *
467  * @param con_handle the connection handle
468  * @param url the url
469  * @param cls the RequestHandle
470  */
471 static void
472 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
473                    const char* url,
474                    void *cls)
475 {
476   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
477   struct RequestHandle *handle = cls;
478   struct EgoEntry *ego_entry;
479   char *identity;
480
481   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
482               handle->url);
483   if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
484        strlen (handle->url))
485   {
486     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
487     GNUNET_SCHEDULER_add_now (&do_error, handle);
488     return;
489   }
490   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
491
492   for (ego_entry = handle->ego_head;
493        NULL != ego_entry;
494        ego_entry = ego_entry->next)
495     if (0 == strcmp (identity, ego_entry->identifier))
496       break;
497   handle->resp_object = json_array ();
498
499   if (NULL == ego_entry)
500   {
501     //Done
502     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
503                 identity);
504     GNUNET_SCHEDULER_add_now (&return_response, handle);
505     return;
506   }
507   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
508   handle->idp = GNUNET_RECLAIM_connect (cfg);
509   handle->ticket_it = GNUNET_RECLAIM_ticket_iteration_start (handle->idp,
510                                                              priv_key,
511                                                              &collect_error_cb,
512                                                              handle,
513                                                              &ticket_collect,
514                                                              handle,
515                                                              &collect_finished_cb,
516                                                              handle);
517 }
518
519
520 static void
521 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
522                     const char* url,
523                     void *cls)
524 {
525   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
526   const char* identity;
527   struct RequestHandle *handle = cls;
528   struct EgoEntry *ego_entry;
529   struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute;
530   struct GNUNET_TIME_Relative exp;
531   char term_data[handle->rest_handle->data_size+1];
532   json_t *data_json;
533   json_error_t err;
534   struct GNUNET_JSON_Specification attrspec[] = {
535     GNUNET_RECLAIM_JSON_spec_claim (&attribute),
536     GNUNET_JSON_spec_end()
537   };
538
539   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
540               handle->url);
541   if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >=
542        strlen (handle->url))
543   {
544     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
545     GNUNET_SCHEDULER_add_now (&do_error, handle);
546     return;
547   }
548   identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
549
550   for (ego_entry = handle->ego_head;
551        NULL != ego_entry;
552        ego_entry = ego_entry->next)
553     if (0 == strcmp (identity, ego_entry->identifier))
554       break;
555
556   if (NULL == ego_entry)
557   {
558     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
559                 "Identity unknown (%s)\n", identity);
560     return;
561   }
562   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
563
564   if (0 >= handle->rest_handle->data_size)
565   {
566     GNUNET_SCHEDULER_add_now (&do_error, handle);
567     return;
568   }
569
570   term_data[handle->rest_handle->data_size] = '\0';
571   GNUNET_memcpy (term_data,
572                  handle->rest_handle->data,
573                  handle->rest_handle->data_size);
574   data_json = json_loads (term_data,
575                           JSON_DECODE_ANY,
576                           &err);
577   GNUNET_assert (GNUNET_OK ==
578                  GNUNET_JSON_parse (data_json, attrspec,
579                                     NULL, NULL));
580   json_decref (data_json);
581   if (NULL == attribute)
582   {
583     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
584                 "Unable to parse attribute from %s\n",
585                 term_data);
586     GNUNET_SCHEDULER_add_now (&do_error, handle);
587     return;
588   }
589   handle->idp = GNUNET_RECLAIM_connect (cfg);
590   exp = GNUNET_TIME_UNIT_HOURS;
591   handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
592                                                    identity_priv,
593                                                    attribute,
594                                                    &exp,
595                                                    &finished_cont,
596                                                    handle);
597   GNUNET_JSON_parse_free (attrspec);
598 }
599
600
601
602 /**
603  * Collect all attributes for an ego
604  *
605  */
606 static void
607 attr_collect (void *cls,
608               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
609               const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
610 {
611   struct RequestHandle *handle = cls;
612   json_t *attr_obj;
613   const char* type;
614   char* tmp_value;
615
616   if ((NULL == attr->name) || (NULL == attr->data))
617   {
618     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
619     return;
620   }
621
622   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
623               attr->name);
624
625   tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
626                                                         attr->data,
627                                                         attr->data_size);
628
629   attr_obj = json_object ();
630   json_object_set_new (attr_obj,
631                    "value",
632                    json_string (tmp_value));
633   json_object_set_new (attr_obj,
634                    "name",
635                    json_string (attr->name));
636   type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
637   json_object_set_new (attr_obj,
638                        "type",
639                        json_string (type));
640   json_array_append (handle->resp_object,
641                      attr_obj);
642   json_decref (attr_obj);
643   GNUNET_free(tmp_value);
644   GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
645 }
646
647
648
649 /**
650  * List attributes for identity request
651  *
652  * @param con_handle the connection handle
653  * @param url the url
654  * @param cls the RequestHandle
655  */
656 static void
657 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
658                      const char* url,
659                      void *cls)
660 {
661   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
662   struct RequestHandle *handle = cls;
663   struct EgoEntry *ego_entry;
664   char *identity;
665
666   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
667               handle->url);
668   if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >=
669        strlen (handle->url))
670   {
671     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
672     GNUNET_SCHEDULER_add_now (&do_error, handle);
673     return;
674   }
675   identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
676
677   for (ego_entry = handle->ego_head;
678        NULL != ego_entry;
679        ego_entry = ego_entry->next)
680     if (0 == strcmp (identity, ego_entry->identifier))
681       break;
682   handle->resp_object = json_array ();
683
684
685   if (NULL == ego_entry)
686   {
687     //Done
688     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
689                 identity);
690     GNUNET_SCHEDULER_add_now (&return_response, handle);
691     return;
692   }
693   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
694   handle->idp = GNUNET_RECLAIM_connect (cfg);
695   handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
696                                                          priv_key,
697                                                          &collect_error_cb,
698                                                          handle,
699                                                          &attr_collect,
700                                                          handle,
701                                                          &collect_finished_cb,
702                                                          handle);
703 }
704
705
706 static void
707 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
708                     const char* url,
709                     void *cls)
710 {
711   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
712   struct RequestHandle *handle = cls;
713   struct EgoEntry *ego_entry;
714   struct GNUNET_RECLAIM_Ticket *ticket;
715   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
716   char term_data[handle->rest_handle->data_size+1];
717   json_t *data_json;
718   json_error_t err;
719   struct GNUNET_JSON_Specification tktspec[] = {
720     GNUNET_RECLAIM_JSON_spec_ticket (&ticket),
721     GNUNET_JSON_spec_end()
722   };
723
724   if (0 >= handle->rest_handle->data_size)
725   {
726     GNUNET_SCHEDULER_add_now (&do_error, handle);
727     return;
728   }
729
730   term_data[handle->rest_handle->data_size] = '\0';
731   GNUNET_memcpy (term_data,
732                  handle->rest_handle->data,
733                  handle->rest_handle->data_size);
734   data_json = json_loads (term_data,
735                           JSON_DECODE_ANY,
736                           &err);
737   GNUNET_assert (GNUNET_OK ==
738                  GNUNET_JSON_parse (data_json, tktspec,
739                                     NULL, NULL));
740   json_decref (data_json);
741   if (NULL == ticket)
742   {
743     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
744                 "Unable to parse ticket from %s\n",
745                 term_data);
746     GNUNET_SCHEDULER_add_now (&do_error, handle);
747     return;
748   }
749   if (GNUNET_OK != GNUNET_JSON_parse (data_json,
750                                       tktspec,
751                                       NULL, NULL))
752   {
753     handle->emsg = GNUNET_strdup ("Not a ticket!\n");
754     GNUNET_SCHEDULER_add_now (&do_error, handle);
755     GNUNET_JSON_parse_free (tktspec);
756     json_decref (data_json);
757     return;
758   }
759
760   for (ego_entry = handle->ego_head;
761        NULL != ego_entry;
762        ego_entry = ego_entry->next)
763   {
764     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
765                                         &tmp_pk);
766     if (0 == memcmp (&ticket->identity,
767                      &tmp_pk,
768                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
769       break;
770   }
771   if (NULL == ego_entry)
772   {
773     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
774                 "Identity unknown\n");
775     GNUNET_JSON_parse_free (tktspec);
776     return;
777   }
778   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
779
780   handle->idp = GNUNET_RECLAIM_connect (cfg);
781   handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
782                                                  identity_priv,
783                                                  ticket,
784                                                  &finished_cont,
785                                                  handle);
786   GNUNET_JSON_parse_free (tktspec);
787 }
788
789 static void
790 consume_cont (void *cls,
791               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
792               const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
793 {
794   struct RequestHandle *handle = cls;
795   char *val_str;
796   json_t *value;
797
798   if (NULL == identity)
799   {
800     GNUNET_SCHEDULER_add_now (&return_response, handle);
801     return;
802   }
803
804   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
805               attr->name);
806   val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
807                                                       attr->data,
808                                                       attr->data_size);
809   if (NULL == val_str)
810   {
811     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to parse value for: %s\n",
812                 attr->name);
813     return;
814   }
815   value = json_string(val_str);
816   json_object_set_new (handle->resp_object,
817                        attr->name,
818                        value);
819   json_decref (value);
820   GNUNET_free (val_str);
821 }
822
823 static void
824 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
825                      const char* url,
826                      void *cls)
827 {
828   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
829   struct RequestHandle *handle = cls;
830   struct EgoEntry *ego_entry;
831   struct GNUNET_RECLAIM_Ticket *ticket;
832   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
833   char term_data[handle->rest_handle->data_size+1];
834   json_t *data_json;
835   json_error_t err;
836   struct GNUNET_JSON_Specification tktspec[] = {
837     GNUNET_RECLAIM_JSON_spec_ticket (&ticket),
838     GNUNET_JSON_spec_end ()
839   };
840
841   if (0 >= handle->rest_handle->data_size)
842   {
843     GNUNET_SCHEDULER_add_now (&do_error, handle);
844     return;
845   }
846
847   term_data[handle->rest_handle->data_size] = '\0';
848   GNUNET_memcpy (term_data,
849                  handle->rest_handle->data,
850                  handle->rest_handle->data_size);
851   data_json = json_loads (term_data,
852                           JSON_DECODE_ANY,
853                           &err);
854   if (NULL == data_json)
855   {
856     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
857                 "Unable to parse JSON Object from %s\n",
858                 term_data);
859     GNUNET_SCHEDULER_add_now (&do_error, handle);
860     return;
861   }
862   if (GNUNET_OK != GNUNET_JSON_parse (data_json,
863                                       tktspec,
864                                       NULL, NULL))
865   {
866     handle->emsg = GNUNET_strdup ("Not a ticket!\n");
867     GNUNET_SCHEDULER_add_now (&do_error, handle);
868     GNUNET_JSON_parse_free(tktspec);
869     json_decref (data_json);
870     return;
871   }
872   for (ego_entry = handle->ego_head;
873        NULL != ego_entry;
874        ego_entry = ego_entry->next)
875   {
876     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
877                                         &tmp_pk);
878     if (0 == memcmp (&ticket->audience,
879                      &tmp_pk,
880                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
881       break;
882   }
883   if (NULL == ego_entry)
884   {
885     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
886                 "Identity unknown\n");
887     GNUNET_JSON_parse_free (tktspec);
888     return;
889   }
890   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
891   handle->resp_object = json_object ();
892   handle->idp = GNUNET_RECLAIM_connect (cfg);
893   handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
894                                                   identity_priv,
895                                                   ticket,
896                                                   &consume_cont,
897                                                   handle);
898   GNUNET_JSON_parse_free (tktspec);
899 }
900
901
902
903 /**
904  * Respond to OPTIONS request
905  *
906  * @param con_handle the connection handle
907  * @param url the url
908  * @param cls the RequestHandle
909  */
910 static void
911 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
912               const char* url,
913               void *cls)
914 {
915   struct MHD_Response *resp;
916   struct RequestHandle *handle = cls;
917
918   //For now, independent of path return all options
919   resp = GNUNET_REST_create_response (NULL);
920   MHD_add_response_header (resp,
921                            "Access-Control-Allow-Methods",
922                            allow_methods);
923   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
924   cleanup_handle (handle);
925   return;
926 }
927
928 /**
929  * Handle rest request
930  *
931  * @param handle the request handle
932  */
933 static void
934 init_cont (struct RequestHandle *handle)
935 {
936   struct GNUNET_REST_RequestHandlerError err;
937   static const struct GNUNET_REST_RequestHandler handlers[] = {
938     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &list_attribute_cont},
939     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &add_attribute_cont},
940     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
941     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
942     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
943     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM,
944       &options_cont},
945     GNUNET_REST_HANDLER_END
946   };
947
948   if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
949                                                handlers,
950                                                &err,
951                                                handle))
952   {
953     handle->response_code = err.error_code;
954     GNUNET_SCHEDULER_add_now (&do_error, handle);
955   }
956 }
957
958 /**
959  * If listing is enabled, prints information about the egos.
960  *
961  * This function is initially called for all egos and then again
962  * whenever a ego's identifier changes or if it is deleted.  At the
963  * end of the initial pass over all egos, the function is once called
964  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
965  * be invoked in the future or that there was an error.
966  *
967  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
968  * this function is only called ONCE, and 'NULL' being passed in
969  * 'ego' does indicate an error (i.e. name is taken or no default
970  * value is known).  If 'ego' is non-NULL and if '*ctx'
971  * is set in those callbacks, the value WILL be passed to a subsequent
972  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
973  * that one was not NULL).
974  *
975  * When an identity is renamed, this function is called with the
976  * (known) ego but the NEW identifier.
977  *
978  * When an identity is deleted, this function is called with the
979  * (known) ego and "NULL" for the 'identifier'.  In this case,
980  * the 'ego' is henceforth invalid (and the 'ctx' should also be
981  * cleaned up).
982  *
983  * @param cls closure
984  * @param ego ego handle
985  * @param ctx context for application to store data for this ego
986  *                 (during the lifetime of this process, initially NULL)
987  * @param identifier identifier assigned by the user for this ego,
988  *                   NULL if the user just deleted the ego and it
989  *                   must thus no longer be used
990  */
991 static void
992 list_ego (void *cls,
993           struct GNUNET_IDENTITY_Ego *ego,
994           void **ctx,
995           const char *identifier)
996 {
997   struct RequestHandle *handle = cls;
998   struct EgoEntry *ego_entry;
999   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1000
1001   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1002   {
1003     handle->state = ID_REST_STATE_POST_INIT;
1004     init_cont (handle);
1005     return;
1006   }
1007   if (ID_REST_STATE_INIT == handle->state) {
1008     ego_entry = GNUNET_new (struct EgoEntry);
1009     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1010     ego_entry->keystring =
1011       GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1012     ego_entry->ego = ego;
1013     ego_entry->identifier = GNUNET_strdup (identifier);
1014     GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1015   }
1016
1017 }
1018
1019 static void
1020 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1021                               GNUNET_REST_ResultProcessor proc,
1022                               void *proc_cls)
1023 {
1024   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1025   handle->response_code = 0;
1026   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1027   handle->proc_cls = proc_cls;
1028   handle->proc = proc;
1029   handle->state = ID_REST_STATE_INIT;
1030   handle->rest_handle = rest_handle;
1031
1032   handle->url = GNUNET_strdup (rest_handle->url);
1033   if (handle->url[strlen (handle->url)-1] == '/')
1034     handle->url[strlen (handle->url)-1] = '\0';
1035   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1036               "Connecting...\n");
1037   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1038                                                      &list_ego,
1039                                                      handle);
1040   handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
1041   handle->timeout_task =
1042     GNUNET_SCHEDULER_add_delayed (handle->timeout,
1043                                   &do_timeout,
1044                                   handle);
1045   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1046               "Connected\n");
1047 }
1048
1049 /**
1050  * Entry point for the plugin.
1051  *
1052  * @param cls Config info
1053  * @return NULL on error, otherwise the plugin context
1054  */
1055 void *
1056 libgnunet_plugin_rest_reclaim_init (void *cls)
1057 {
1058   static struct Plugin plugin;
1059   struct GNUNET_REST_Plugin *api;
1060
1061   cfg = cls;
1062   if (NULL != plugin.cfg)
1063     return NULL;                /* can only initialize once! */
1064   memset (&plugin, 0, sizeof (struct Plugin));
1065   plugin.cfg = cfg;
1066   api = GNUNET_new (struct GNUNET_REST_Plugin);
1067   api->cls = &plugin;
1068   api->name = GNUNET_REST_API_NS_RECLAIM;
1069   api->process_request = &rest_identity_process_request;
1070   GNUNET_asprintf (&allow_methods,
1071                    "%s, %s, %s, %s, %s",
1072                    MHD_HTTP_METHOD_GET,
1073                    MHD_HTTP_METHOD_POST,
1074                    MHD_HTTP_METHOD_PUT,
1075                    MHD_HTTP_METHOD_DELETE,
1076                    MHD_HTTP_METHOD_OPTIONS);
1077
1078   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1079               _("Identity Provider REST API initialized\n"));
1080   return api;
1081 }
1082
1083
1084 /**
1085  * Exit point from the plugin.
1086  *
1087  * @param cls the plugin context (as returned by "init")
1088  * @return always NULL
1089  */
1090 void *
1091 libgnunet_plugin_rest_reclaim_done (void *cls)
1092 {
1093   struct GNUNET_REST_Plugin *api = cls;
1094   struct Plugin *plugin = api->cls;
1095   plugin->cfg = NULL;
1096
1097   GNUNET_free_non_null (allow_methods);
1098   GNUNET_free (api);
1099   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1100               "Identity Provider REST plugin is finished\n");
1101   return NULL;
1102 }
1103
1104 /* end of plugin_rest_reclaim.c */