revert
[oweals/gnunet.git] / src / rest-plugins / 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 /**
19  * @author Martin Schanzenbach
20  * @author Philippe Buschmann
21  * @file reclaim/plugin_rest_reclaim.c
22  * @brief GNUnet reclaim REST plugin
23  *
24  */
25
26 #include "platform.h"
27 #include "gnunet_rest_plugin.h"
28 #include "gnunet_identity_service.h"
29 #include "gnunet_gns_service.h"
30 #include "gnunet_gnsrecord_lib.h"
31 #include "gnunet_namestore_service.h"
32 #include "gnunet_rest_lib.h"
33 #include "gnunet_jsonapi_lib.h"
34 #include "gnunet_jsonapi_util.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   handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
591                                                    identity_priv,
592                                                    attribute,
593                                                    &exp,
594                                                    &finished_cont,
595                                                    handle);
596   GNUNET_JSON_parse_free (attrspec);
597 }
598
599
600
601 /**
602  * Collect all attributes for an ego
603  *
604  */
605 static void
606 attr_collect (void *cls,
607               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
608               const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
609 {
610   struct RequestHandle *handle = cls;
611   json_t *attr_obj;
612   const char* type;
613   char* tmp_value;
614
615   if ((NULL == attr->name) || (NULL == attr->data))
616   {
617     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
618     return;
619   }
620
621   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
622               attr->name);
623
624   tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
625                                                         attr->data,
626                                                         attr->data_size);
627
628   attr_obj = json_object ();
629   json_object_set_new (attr_obj,
630                    "value",
631                    json_string (tmp_value));
632   json_object_set_new (attr_obj,
633                    "name",
634                    json_string (attr->name));
635   type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
636   json_object_set_new (attr_obj,
637                        "type",
638                        json_string (type));
639   json_array_append (handle->resp_object,
640                      attr_obj);
641   json_decref (attr_obj);
642   GNUNET_free(tmp_value);
643   GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
644 }
645
646
647
648 /**
649  * List attributes for identity request
650  *
651  * @param con_handle the connection handle
652  * @param url the url
653  * @param cls the RequestHandle
654  */
655 static void
656 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
657                      const char* url,
658                      void *cls)
659 {
660   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
661   struct RequestHandle *handle = cls;
662   struct EgoEntry *ego_entry;
663   char *identity;
664
665   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
666               handle->url);
667   if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >=
668        strlen (handle->url))
669   {
670     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
671     GNUNET_SCHEDULER_add_now (&do_error, handle);
672     return;
673   }
674   identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
675
676   for (ego_entry = handle->ego_head;
677        NULL != ego_entry;
678        ego_entry = ego_entry->next)
679     if (0 == strcmp (identity, ego_entry->identifier))
680       break;
681   handle->resp_object = json_array ();
682
683
684   if (NULL == ego_entry)
685   {
686     //Done
687     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
688                 identity);
689     GNUNET_SCHEDULER_add_now (&return_response, handle);
690     return;
691   }
692   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
693   handle->idp = GNUNET_RECLAIM_connect (cfg);
694   handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
695                                                          priv_key,
696                                                          &collect_error_cb,
697                                                          handle,
698                                                          &attr_collect,
699                                                          handle,
700                                                          &collect_finished_cb,
701                                                          handle);
702 }
703
704
705 static void
706 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
707                     const char* url,
708                     void *cls)
709 {
710   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
711   struct RequestHandle *handle = cls;
712   struct EgoEntry *ego_entry;
713   struct GNUNET_RECLAIM_Ticket *ticket;
714   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
715   char term_data[handle->rest_handle->data_size+1];
716   json_t *data_json;
717   json_error_t err;
718   struct GNUNET_JSON_Specification tktspec[] = {
719     GNUNET_RECLAIM_JSON_spec_ticket (&ticket),
720     GNUNET_JSON_spec_end()
721   };
722
723   if (0 >= handle->rest_handle->data_size)
724   {
725     GNUNET_SCHEDULER_add_now (&do_error, handle);
726     return;
727   }
728
729   term_data[handle->rest_handle->data_size] = '\0';
730   GNUNET_memcpy (term_data,
731                  handle->rest_handle->data,
732                  handle->rest_handle->data_size);
733   data_json = json_loads (term_data,
734                           JSON_DECODE_ANY,
735                           &err);
736   GNUNET_assert (GNUNET_OK ==
737                  GNUNET_JSON_parse (data_json, tktspec,
738                                     NULL, NULL));
739   json_decref (data_json);
740   if (NULL == ticket)
741   {
742     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
743                 "Unable to parse ticket from %s\n",
744                 term_data);
745     GNUNET_SCHEDULER_add_now (&do_error, handle);
746     return;
747   }
748   if (GNUNET_OK != GNUNET_JSON_parse (data_json,
749                                       tktspec,
750                                       NULL, NULL))
751   {
752     handle->emsg = GNUNET_strdup ("Not a ticket!\n");
753     GNUNET_SCHEDULER_add_now (&do_error, handle);
754     GNUNET_JSON_parse_free (tktspec);
755     json_decref (data_json);
756     return;
757   }
758
759   for (ego_entry = handle->ego_head;
760        NULL != ego_entry;
761        ego_entry = ego_entry->next)
762   {
763     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
764                                         &tmp_pk);
765     if (0 == memcmp (&ticket->identity,
766                      &tmp_pk,
767                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
768       break;
769   }
770   if (NULL == ego_entry)
771   {
772     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
773                 "Identity unknown\n");
774     GNUNET_JSON_parse_free (tktspec);
775     return;
776   }
777   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
778
779   handle->idp = GNUNET_RECLAIM_connect (cfg);
780   handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
781                                                  identity_priv,
782                                                  ticket,
783                                                  &finished_cont,
784                                                  handle);
785   GNUNET_JSON_parse_free (tktspec);
786 }
787
788 static void
789 consume_cont (void *cls,
790               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
791               const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
792 {
793   struct RequestHandle *handle = cls;
794   char *val_str;
795   json_t *value;
796
797   if (NULL == identity)
798   {
799     GNUNET_SCHEDULER_add_now (&return_response, handle);
800     return;
801   }
802
803   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
804               attr->name);
805   val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
806                                                       attr->data,
807                                                       attr->data_size);
808   if (NULL == val_str)
809   {
810     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to parse value for: %s\n",
811                 attr->name);
812     return;
813   }
814   value = json_string(val_str);
815   json_object_set_new (handle->resp_object,
816                        attr->name,
817                        value);
818   json_decref (value);
819   GNUNET_free (val_str);
820 }
821
822 static void
823 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
824                      const char* url,
825                      void *cls)
826 {
827   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
828   struct RequestHandle *handle = cls;
829   struct EgoEntry *ego_entry;
830   struct GNUNET_RECLAIM_Ticket *ticket;
831   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
832   char term_data[handle->rest_handle->data_size+1];
833   json_t *data_json;
834   json_error_t err;
835   struct GNUNET_JSON_Specification tktspec[] = {
836     GNUNET_RECLAIM_JSON_spec_ticket (&ticket),
837     GNUNET_JSON_spec_end ()
838   };
839
840   if (0 >= handle->rest_handle->data_size)
841   {
842     GNUNET_SCHEDULER_add_now (&do_error, handle);
843     return;
844   }
845
846   term_data[handle->rest_handle->data_size] = '\0';
847   GNUNET_memcpy (term_data,
848                  handle->rest_handle->data,
849                  handle->rest_handle->data_size);
850   data_json = json_loads (term_data,
851                           JSON_DECODE_ANY,
852                           &err);
853   if (NULL == data_json)
854   {
855     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
856                 "Unable to parse JSON Object from %s\n",
857                 term_data);
858     GNUNET_SCHEDULER_add_now (&do_error, handle);
859     return;
860   }
861   if (GNUNET_OK != GNUNET_JSON_parse (data_json,
862                                       tktspec,
863                                       NULL, NULL))
864   {
865     handle->emsg = GNUNET_strdup ("Not a ticket!\n");
866     GNUNET_SCHEDULER_add_now (&do_error, handle);
867     GNUNET_JSON_parse_free(tktspec);
868     json_decref (data_json);
869     return;
870   }
871   for (ego_entry = handle->ego_head;
872        NULL != ego_entry;
873        ego_entry = ego_entry->next)
874   {
875     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
876                                         &tmp_pk);
877     if (0 == memcmp (&ticket->audience,
878                      &tmp_pk,
879                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
880       break;
881   }
882   if (NULL == ego_entry)
883   {
884     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
885                 "Identity unknown\n");
886     GNUNET_JSON_parse_free (tktspec);
887     return;
888   }
889   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
890   handle->resp_object = json_object ();
891   handle->idp = GNUNET_RECLAIM_connect (cfg);
892   handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
893                                                   identity_priv,
894                                                   ticket,
895                                                   &consume_cont,
896                                                   handle);
897   GNUNET_JSON_parse_free (tktspec);
898 }
899
900
901
902 /**
903  * Respond to OPTIONS request
904  *
905  * @param con_handle the connection handle
906  * @param url the url
907  * @param cls the RequestHandle
908  */
909 static void
910 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
911               const char* url,
912               void *cls)
913 {
914   struct MHD_Response *resp;
915   struct RequestHandle *handle = cls;
916
917   //For now, independent of path return all options
918   resp = GNUNET_REST_create_response (NULL);
919   MHD_add_response_header (resp,
920                            "Access-Control-Allow-Methods",
921                            allow_methods);
922   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
923   cleanup_handle (handle);
924   return;
925 }
926
927 /**
928  * Handle rest request
929  *
930  * @param handle the request handle
931  */
932 static void
933 init_cont (struct RequestHandle *handle)
934 {
935   struct GNUNET_REST_RequestHandlerError err;
936   static const struct GNUNET_REST_RequestHandler handlers[] = {
937     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &list_attribute_cont},
938     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &add_attribute_cont},
939     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
940     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
941     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
942     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM,
943       &options_cont},
944     GNUNET_REST_HANDLER_END
945   };
946
947   if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
948                                                handlers,
949                                                &err,
950                                                handle))
951   {
952     handle->response_code = err.error_code;
953     GNUNET_SCHEDULER_add_now (&do_error, handle);
954   }
955 }
956
957 /**
958  * If listing is enabled, prints information about the egos.
959  *
960  * This function is initially called for all egos and then again
961  * whenever a ego's identifier changes or if it is deleted.  At the
962  * end of the initial pass over all egos, the function is once called
963  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
964  * be invoked in the future or that there was an error.
965  *
966  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
967  * this function is only called ONCE, and 'NULL' being passed in
968  * 'ego' does indicate an error (i.e. name is taken or no default
969  * value is known).  If 'ego' is non-NULL and if '*ctx'
970  * is set in those callbacks, the value WILL be passed to a subsequent
971  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
972  * that one was not NULL).
973  *
974  * When an identity is renamed, this function is called with the
975  * (known) ego but the NEW identifier.
976  *
977  * When an identity is deleted, this function is called with the
978  * (known) ego and "NULL" for the 'identifier'.  In this case,
979  * the 'ego' is henceforth invalid (and the 'ctx' should also be
980  * cleaned up).
981  *
982  * @param cls closure
983  * @param ego ego handle
984  * @param ctx context for application to store data for this ego
985  *                 (during the lifetime of this process, initially NULL)
986  * @param identifier identifier assigned by the user for this ego,
987  *                   NULL if the user just deleted the ego and it
988  *                   must thus no longer be used
989  */
990 static void
991 list_ego (void *cls,
992           struct GNUNET_IDENTITY_Ego *ego,
993           void **ctx,
994           const char *identifier)
995 {
996   struct RequestHandle *handle = cls;
997   struct EgoEntry *ego_entry;
998   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
999
1000   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1001   {
1002     handle->state = ID_REST_STATE_POST_INIT;
1003     init_cont (handle);
1004     return;
1005   }
1006   if (ID_REST_STATE_INIT == handle->state) {
1007     ego_entry = GNUNET_new (struct EgoEntry);
1008     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1009     ego_entry->keystring =
1010       GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1011     ego_entry->ego = ego;
1012     ego_entry->identifier = GNUNET_strdup (identifier);
1013     GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1014   }
1015
1016 }
1017
1018 static void
1019 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1020                               GNUNET_REST_ResultProcessor proc,
1021                               void *proc_cls)
1022 {
1023   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1024   handle->response_code = 0;
1025   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1026   handle->proc_cls = proc_cls;
1027   handle->proc = proc;
1028   handle->state = ID_REST_STATE_INIT;
1029   handle->rest_handle = rest_handle;
1030
1031   handle->url = GNUNET_strdup (rest_handle->url);
1032   if (handle->url[strlen (handle->url)-1] == '/')
1033     handle->url[strlen (handle->url)-1] = '\0';
1034   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1035               "Connecting...\n");
1036   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1037                                                      &list_ego,
1038                                                      handle);
1039   handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
1040   handle->timeout_task =
1041     GNUNET_SCHEDULER_add_delayed (handle->timeout,
1042                                   &do_timeout,
1043                                   handle);
1044   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1045               "Connected\n");
1046 }
1047
1048 /**
1049  * Entry point for the plugin.
1050  *
1051  * @param cls Config info
1052  * @return NULL on error, otherwise the plugin context
1053  */
1054 void *
1055 libgnunet_plugin_rest_reclaim_init (void *cls)
1056 {
1057   static struct Plugin plugin;
1058   struct GNUNET_REST_Plugin *api;
1059
1060   cfg = cls;
1061   if (NULL != plugin.cfg)
1062     return NULL;                /* can only initialize once! */
1063   memset (&plugin, 0, sizeof (struct Plugin));
1064   plugin.cfg = cfg;
1065   api = GNUNET_new (struct GNUNET_REST_Plugin);
1066   api->cls = &plugin;
1067   api->name = GNUNET_REST_API_NS_RECLAIM;
1068   api->process_request = &rest_identity_process_request;
1069   GNUNET_asprintf (&allow_methods,
1070                    "%s, %s, %s, %s, %s",
1071                    MHD_HTTP_METHOD_GET,
1072                    MHD_HTTP_METHOD_POST,
1073                    MHD_HTTP_METHOD_PUT,
1074                    MHD_HTTP_METHOD_DELETE,
1075                    MHD_HTTP_METHOD_OPTIONS);
1076
1077   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1078               _("Identity Provider REST API initialized\n"));
1079   return api;
1080 }
1081
1082
1083 /**
1084  * Exit point from the plugin.
1085  *
1086  * @param cls the plugin context (as returned by "init")
1087  * @return always NULL
1088  */
1089 void *
1090 libgnunet_plugin_rest_reclaim_done (void *cls)
1091 {
1092   struct GNUNET_REST_Plugin *api = cls;
1093   struct Plugin *plugin = api->cls;
1094   plugin->cfg = NULL;
1095
1096   GNUNET_free_non_null (allow_methods);
1097   GNUNET_free (api);
1098   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1099               "Identity Provider REST plugin is finished\n");
1100   return NULL;
1101 }
1102
1103 /* end of plugin_rest_reclaim.c */