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