ftbfs
[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   if (GNUNET_RECLAIM_id_is_zero (&attr->attestation))
968     json_object_set_new (attr_obj, "flag", json_string ("0"));
969   else
970     json_object_set_new (attr_obj, "flag", json_string ("1"));
971   type = GNUNET_RECLAIM_attribute_number_to_typename (attr->type);
972   json_object_set_new (attr_obj, "type", json_string (type));
973   id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id,
974                                                 sizeof(attr->id));
975   json_object_set_new (attr_obj, "id", json_string (id_str));
976   id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->attestation,
977                                                 sizeof(attr->attestation));
978   json_object_set_new (attr_obj, "attestation", json_string (id_str));
979   json_array_append (handle->resp_object, attr_obj);
980   json_decref (attr_obj);
981   GNUNET_free (tmp_value);
982   GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
983 }
984
985
986 /**
987  * List attributes for identity request
988  *
989  * @param con_handle the connection handle
990  * @param url the url
991  * @param cls the RequestHandle
992  */
993 static void
994 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
995                      const char *url,
996                      void *cls)
997 {
998   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
999   struct RequestHandle *handle = cls;
1000   struct EgoEntry *ego_entry;
1001   char *identity;
1002
1003   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1004               "Getting attributes for %s.\n",
1005               handle->url);
1006   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1007   {
1008     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1009     GNUNET_SCHEDULER_add_now (&do_error, handle);
1010     return;
1011   }
1012   identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
1013
1014   for (ego_entry = handle->ego_head; NULL != ego_entry;
1015        ego_entry = ego_entry->next)
1016     if (0 == strcmp (identity, ego_entry->identifier))
1017       break;
1018   handle->resp_object = json_array ();
1019
1020
1021   if (NULL == ego_entry)
1022   {
1023     // Done
1024     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1025     GNUNET_SCHEDULER_add_now (&return_response, handle);
1026     return;
1027   }
1028   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1029   handle->idp = GNUNET_RECLAIM_connect (cfg);
1030   handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
1031                                                          priv_key,
1032                                                          &collect_error_cb,
1033                                                          handle,
1034                                                          &attr_collect,
1035                                                          handle,
1036                                                          &collect_finished_cb,
1037                                                          handle);
1038 }
1039
1040
1041 /**
1042  * List attributes for identity request
1043  *
1044  * @param con_handle the connection handle
1045  * @param url the url
1046  * @param cls the RequestHandle
1047  */
1048 static void
1049 delete_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1050                        const char *url,
1051                        void *cls)
1052 {
1053   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1054   struct RequestHandle *handle = cls;
1055   struct GNUNET_RECLAIM_Attribute attr;
1056   struct EgoEntry *ego_entry;
1057   char *identity_id_str;
1058   char *identity;
1059   char *id;
1060
1061   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attributes.\n");
1062   if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1063   {
1064     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1065     GNUNET_SCHEDULER_add_now (&do_error, handle);
1066     return;
1067   }
1068   identity_id_str =
1069     strdup (handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1);
1070   identity = strtok (identity_id_str, "/");
1071   id = strtok (NULL, "/");
1072   if ((NULL == identity) || (NULL == id))
1073   {
1074     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
1075     GNUNET_free (identity_id_str);
1076     GNUNET_SCHEDULER_add_now (&do_error, handle);
1077     return;
1078   }
1079
1080   for (ego_entry = handle->ego_head; NULL != ego_entry;
1081        ego_entry = ego_entry->next)
1082     if (0 == strcmp (identity, ego_entry->identifier))
1083       break;
1084   handle->resp_object = json_array ();
1085   if (NULL == ego_entry)
1086   {
1087     // Done
1088     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1089     GNUNET_free (identity_id_str);
1090     GNUNET_SCHEDULER_add_now (&return_response, handle);
1091     return;
1092   }
1093   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1094   handle->idp = GNUNET_RECLAIM_connect (cfg);
1095   memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Attribute));
1096   GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
1097   attr.name = "";
1098   handle->idp_op = GNUNET_RECLAIM_attribute_delete (handle->idp,
1099                                                     priv_key,
1100                                                     &attr,
1101                                                     &delete_finished_cb,
1102                                                     handle);
1103   GNUNET_free (identity_id_str);
1104 }
1105
1106
1107 static void
1108 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1109                     const char *url,
1110                     void *cls)
1111 {
1112   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1113   struct RequestHandle *handle = cls;
1114   struct EgoEntry *ego_entry;
1115   struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1116   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1117   char term_data[handle->rest_handle->data_size + 1];
1118   json_t *data_json;
1119   json_error_t err;
1120   struct GNUNET_JSON_Specification tktspec[] =
1121   { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1122
1123   if (0 >= handle->rest_handle->data_size)
1124   {
1125     GNUNET_SCHEDULER_add_now (&do_error, handle);
1126     return;
1127   }
1128
1129   term_data[handle->rest_handle->data_size] = '\0';
1130   GNUNET_memcpy (term_data,
1131                  handle->rest_handle->data,
1132                  handle->rest_handle->data_size);
1133   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1134   if ((NULL == data_json) ||
1135       (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)))
1136   {
1137     handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1138     GNUNET_SCHEDULER_add_now (&do_error, handle);
1139     GNUNET_JSON_parse_free (tktspec);
1140     if (NULL != data_json)
1141       json_decref (data_json);
1142     return;
1143   }
1144   json_decref (data_json);
1145   if (NULL == ticket)
1146   {
1147     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1148                 "Unable to parse ticket from %s\n",
1149                 term_data);
1150     GNUNET_SCHEDULER_add_now (&do_error, handle);
1151     return;
1152   }
1153
1154   for (ego_entry = handle->ego_head; NULL != ego_entry;
1155        ego_entry = ego_entry->next)
1156   {
1157     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1158     if (0 == memcmp (&ticket->identity,
1159                      &tmp_pk,
1160                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1161       break;
1162   }
1163   if (NULL == ego_entry)
1164   {
1165     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1166     GNUNET_JSON_parse_free (tktspec);
1167     return;
1168   }
1169   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1170
1171   handle->idp = GNUNET_RECLAIM_connect (cfg);
1172   handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
1173                                                  identity_priv,
1174                                                  ticket,
1175                                                  &finished_cont,
1176                                                  handle);
1177   GNUNET_JSON_parse_free (tktspec);
1178 }
1179
1180
1181 static void
1182 consume_cont (void *cls,
1183               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1184               const struct GNUNET_RECLAIM_Attribute *attr,
1185               const struct GNUNET_RECLAIM_Attestation *attest)
1186 {
1187   struct RequestHandle *handle = cls;
1188   char *val_str;
1189   json_t *value;
1190
1191   if (NULL == identity)
1192   {
1193     GNUNET_SCHEDULER_add_now (&return_response, handle);
1194     return;
1195   }
1196
1197   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
1198   val_str = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
1199                                                       attr->data,
1200                                                       attr->data_size);
1201   if (NULL == val_str)
1202   {
1203     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1204                 "Failed to parse value for: %s\n",
1205                 attr->name);
1206     return;
1207   }
1208   value = json_string (val_str);
1209   json_object_set_new (handle->resp_object, attr->name, value);
1210   json_decref (value);
1211   GNUNET_free (val_str);
1212 }
1213
1214
1215 static void
1216 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1217                      const char *url,
1218                      void *cls)
1219 {
1220   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1221   struct RequestHandle *handle = cls;
1222   struct EgoEntry *ego_entry;
1223   struct GNUNET_RECLAIM_Ticket *ticket;
1224   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1225   char term_data[handle->rest_handle->data_size + 1];
1226   json_t *data_json;
1227   json_error_t err;
1228   struct GNUNET_JSON_Specification tktspec[] =
1229   { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1230
1231   if (0 >= handle->rest_handle->data_size)
1232   {
1233     GNUNET_SCHEDULER_add_now (&do_error, handle);
1234     return;
1235   }
1236
1237   term_data[handle->rest_handle->data_size] = '\0';
1238   GNUNET_memcpy (term_data,
1239                  handle->rest_handle->data,
1240                  handle->rest_handle->data_size);
1241   data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1242   if (NULL == data_json)
1243   {
1244     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1245                 "Unable to parse JSON Object from %s\n",
1246                 term_data);
1247     GNUNET_SCHEDULER_add_now (&do_error, handle);
1248     return;
1249   }
1250   if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL))
1251   {
1252     handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1253     GNUNET_SCHEDULER_add_now (&do_error, handle);
1254     GNUNET_JSON_parse_free (tktspec);
1255     json_decref (data_json);
1256     return;
1257   }
1258   for (ego_entry = handle->ego_head; NULL != ego_entry;
1259        ego_entry = ego_entry->next)
1260   {
1261     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1262     if (0 == memcmp (&ticket->audience,
1263                      &tmp_pk,
1264                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1265       break;
1266   }
1267   if (NULL == ego_entry)
1268   {
1269     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1270     GNUNET_JSON_parse_free (tktspec);
1271     return;
1272   }
1273   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1274   handle->resp_object = json_object ();
1275   handle->idp = GNUNET_RECLAIM_connect (cfg);
1276   handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
1277                                                   identity_priv,
1278                                                   ticket,
1279                                                   &consume_cont,
1280                                                   handle);
1281   GNUNET_JSON_parse_free (tktspec);
1282 }
1283
1284
1285 /**
1286  * Respond to OPTIONS request
1287  *
1288  * @param con_handle the connection handle
1289  * @param url the url
1290  * @param cls the RequestHandle
1291  */
1292 static void
1293 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1294               const char *url,
1295               void *cls)
1296 {
1297   struct MHD_Response *resp;
1298   struct RequestHandle *handle = cls;
1299
1300   // For now, independent of path return all options
1301   resp = GNUNET_REST_create_response (NULL);
1302   MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
1303   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1304   cleanup_handle (handle);
1305   return;
1306 }
1307
1308
1309 /**
1310  * Handle rest request
1311  *
1312  * @param handle the request handle
1313  */
1314 static void
1315 init_cont (struct RequestHandle *handle)
1316 {
1317   struct GNUNET_REST_RequestHandlerError err;
1318   static const struct GNUNET_REST_RequestHandler handlers[] =
1319   { { MHD_HTTP_METHOD_GET,
1320       GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1321       &list_attribute_cont },
1322     { MHD_HTTP_METHOD_POST,
1323       GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1324       &add_attribute_cont },
1325     { MHD_HTTP_METHOD_DELETE,
1326       GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1327       &delete_attribute_cont },
1328     { MHD_HTTP_METHOD_GET,
1329       GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1330       &list_attestation_cont },
1331     { MHD_HTTP_METHOD_POST,
1332       GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1333       &add_attestation_cont },
1334     { MHD_HTTP_METHOD_DELETE,
1335       GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1336       &delete_attestation_cont },
1337     { MHD_HTTP_METHOD_GET,
1338       GNUNET_REST_API_NS_IDENTITY_TICKETS,
1339       &list_tickets_cont },
1340     { MHD_HTTP_METHOD_POST,
1341       GNUNET_REST_API_NS_IDENTITY_REVOKE,
1342       &revoke_ticket_cont },
1343     { MHD_HTTP_METHOD_POST,
1344       GNUNET_REST_API_NS_IDENTITY_CONSUME,
1345       &consume_ticket_cont },
1346     { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, &options_cont },
1347     GNUNET_REST_HANDLER_END };
1348
1349   if (GNUNET_NO ==
1350       GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1351   {
1352     handle->response_code = err.error_code;
1353     GNUNET_SCHEDULER_add_now (&do_error, handle);
1354   }
1355 }
1356
1357
1358 /**
1359  * If listing is enabled, prints information about the egos.
1360  *
1361  * This function is initially called for all egos and then again
1362  * whenever a ego's identifier changes or if it is deleted.  At the
1363  * end of the initial pass over all egos, the function is once called
1364  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1365  * be invoked in the future or that there was an error.
1366  *
1367  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1368  * this function is only called ONCE, and 'NULL' being passed in
1369  * 'ego' does indicate an error (i.e. name is taken or no default
1370  * value is known).  If 'ego' is non-NULL and if '*ctx'
1371  * is set in those callbacks, the value WILL be passed to a subsequent
1372  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1373  * that one was not NULL).
1374  *
1375  * When an identity is renamed, this function is called with the
1376  * (known) ego but the NEW identifier.
1377  *
1378  * When an identity is deleted, this function is called with the
1379  * (known) ego and "NULL" for the 'identifier'.  In this case,
1380  * the 'ego' is henceforth invalid (and the 'ctx' should also be
1381  * cleaned up).
1382  *
1383  * @param cls closure
1384  * @param ego ego handle
1385  * @param ctx context for application to store data for this ego
1386  *                 (during the lifetime of this process, initially NULL)
1387  * @param identifier identifier assigned by the user for this ego,
1388  *                   NULL if the user just deleted the ego and it
1389  *                   must thus no longer be used
1390  */
1391 static void
1392 list_ego (void *cls,
1393           struct GNUNET_IDENTITY_Ego *ego,
1394           void **ctx,
1395           const char *identifier)
1396 {
1397   struct RequestHandle *handle = cls;
1398   struct EgoEntry *ego_entry;
1399   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1400
1401   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1402   {
1403     handle->state = ID_REST_STATE_POST_INIT;
1404     init_cont (handle);
1405     return;
1406   }
1407   if (ID_REST_STATE_INIT == handle->state)
1408   {
1409     ego_entry = GNUNET_new (struct EgoEntry);
1410     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1411     ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1412     ego_entry->ego = ego;
1413     ego_entry->identifier = GNUNET_strdup (identifier);
1414     GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
1415                                       handle->ego_tail,
1416                                       ego_entry);
1417   }
1418 }
1419
1420
1421 static void
1422 rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1423                                GNUNET_REST_ResultProcessor proc,
1424                                void *proc_cls)
1425 {
1426   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1427
1428   handle->response_code = 0;
1429   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1430   handle->proc_cls = proc_cls;
1431   handle->proc = proc;
1432   handle->state = ID_REST_STATE_INIT;
1433   handle->rest_handle = rest_handle;
1434
1435   handle->url = GNUNET_strdup (rest_handle->url);
1436   if (handle->url[strlen (handle->url) - 1] == '/')
1437     handle->url[strlen (handle->url) - 1] = '\0';
1438   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1439   handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
1440   handle->timeout_task =
1441     GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
1442   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1443 }
1444
1445
1446 /**
1447  * Entry point for the plugin.
1448  *
1449  * @param cls Config info
1450  * @return NULL on error, otherwise the plugin context
1451  */
1452 void *
1453 libgnunet_plugin_rest_reclaim_init (void *cls)
1454 {
1455   static struct Plugin plugin;
1456   struct GNUNET_REST_Plugin *api;
1457
1458   cfg = cls;
1459   if (NULL != plugin.cfg)
1460     return NULL; /* can only initialize once! */
1461   memset (&plugin, 0, sizeof(struct Plugin));
1462   plugin.cfg = cfg;
1463   api = GNUNET_new (struct GNUNET_REST_Plugin);
1464   api->cls = &plugin;
1465   api->name = GNUNET_REST_API_NS_RECLAIM;
1466   api->process_request = &rest_identity_process_request;
1467   GNUNET_asprintf (&allow_methods,
1468                    "%s, %s, %s, %s, %s",
1469                    MHD_HTTP_METHOD_GET,
1470                    MHD_HTTP_METHOD_POST,
1471                    MHD_HTTP_METHOD_PUT,
1472                    MHD_HTTP_METHOD_DELETE,
1473                    MHD_HTTP_METHOD_OPTIONS);
1474
1475   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1476               _ ("Identity Provider REST API initialized\n"));
1477   return api;
1478 }
1479
1480
1481 /**
1482  * Exit point from the plugin.
1483  *
1484  * @param cls the plugin context (as returned by "init")
1485  * @return always NULL
1486  */
1487 void *
1488 libgnunet_plugin_rest_reclaim_done (void *cls)
1489 {
1490   struct GNUNET_REST_Plugin *api = cls;
1491   struct Plugin *plugin = api->cls;
1492
1493   plugin->cfg = NULL;
1494
1495   GNUNET_free_non_null (allow_methods);
1496   GNUNET_free (api);
1497   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1498               "Identity Provider REST plugin is finished\n");
1499   return NULL;
1500 }
1501
1502
1503 /* end of plugin_rest_reclaim.c */