-Merge branch 'master' of ssh://gnunet.org/gnunet into gsoc2018/rest_api
[oweals/gnunet.git] / src / identity / plugin_rest_identity.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2012-2015 GNUnet e.V.
4
5    GNUnet is free software: you can redistribute it and/or modify it
6    under the terms of the GNU Affero General Public License as published
7    by the Free Software Foundation, either version 3 of the License,
8    or (at your option) any later version.
9
10    GNUnet is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Affero General Public License for more details.
14   
15    You should have received a copy of the GNU Affero General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17    */
18 /**
19  * @author Martin Schanzenbach
20  * @author Philippe Buschmann
21  * @file identity/plugin_rest_identity.c
22  * @brief GNUnet Namestore REST plugin
23  *
24  */
25
26 #include "platform.h"
27 #include "gnunet_rest_plugin.h"
28 #include "gnunet_identity_service.h"
29 #include "gnunet_rest_lib.h"
30 #include "microhttpd.h"
31 #include <jansson.h>
32 #include "gnunet_signatures.h"
33
34 /**
35  * REST root namespace
36  */
37 #define GNUNET_REST_API_NS_IDENTITY "/identity"
38
39 /**
40  * State while collecting all egos
41  */
42 #define ID_REST_STATE_INIT 0
43
44 /**
45  * Done collecting egos
46  */
47 #define ID_REST_STATE_POST_INIT 1
48
49 /**
50  * Resource type
51  */
52 #define GNUNET_REST_JSON_IDENTITY_EGO "ego"
53
54 /**
55  * Name attribute
56  */
57 #define GNUNET_REST_JSON_IDENTITY_NAME "name"
58
59 /**
60  * Attribute to rename "name" TODO we changed id to the pubkey
61  * so this can be unified with "name"
62  */
63 #define GNUNET_REST_JSON_IDENTITY_NEWNAME "newname"
64
65 /**
66  * URL parameter to change the subsytem for ego
67  */
68 #define GNUNET_REST_JSON_IDENTITY_SUBSYSTEM "subsystem"
69
70
71 /**
72  * Error messages
73  */
74 #define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
75 #define GNUNET_REST_ERROR_NO_DATA "No data"
76 #define GNUNET_REST_ERROR_DATA_INVALID "Data invalid"
77
78 /**
79  * GNUid token lifetime
80  */
81 #define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000
82
83 /**
84  * The configuration handle
85  */
86 const struct GNUNET_CONFIGURATION_Handle *cfg;
87
88 /**
89  * HTTP methods allows for this plugin
90  */
91 static char* allow_methods;
92
93 /**
94  * @brief struct returned by the initialization function of the plugin
95  */
96 struct Plugin
97 {
98   const struct GNUNET_CONFIGURATION_Handle *cfg;
99 };
100
101 /**
102  * The ego list
103  */
104 struct EgoEntry
105 {
106   /**
107    * DLL
108    */
109   struct EgoEntry *next;
110
111   /**
112    * DLL
113    */
114   struct EgoEntry *prev;
115
116   /**
117    * Ego Identifier
118    */
119   char *identifier;
120
121   /**
122    * Public key string
123    */
124   char *keystring;
125
126   /**
127    * The Ego
128    */
129   struct GNUNET_IDENTITY_Ego *ego;
130 };
131
132
133 struct RequestHandle
134 {
135   /**
136    * Ego list
137    */
138   struct EgoEntry *ego_head;
139
140   /**
141    * Ego list
142    */
143   struct EgoEntry *ego_tail;
144
145   /**
146    * Handle to the rest connection
147    */
148   struct GNUNET_REST_RequestHandle *conndata_handle;
149
150   /**
151    * response code
152    */
153   int response_code;
154
155   /**
156    * The processing state
157    */
158   int state;
159
160   /**
161    * Handle to GNS service.
162    */
163   struct GNUNET_IDENTITY_Handle *identity_handle;
164
165   /**
166    * IDENTITY Operation
167    */
168   struct GNUNET_IDENTITY_Operation *op;
169
170   /**
171    * Desired timeout for the lookup (default is no timeout).
172    */
173   struct GNUNET_TIME_Relative timeout;
174
175   /**
176    * ID of a task associated with the resolution process.
177    */
178   struct GNUNET_SCHEDULER_Task * timeout_task;
179
180   /**
181    * The plugin result processor
182    */
183   GNUNET_REST_ResultProcessor proc;
184
185   /**
186    * The closure of the result processor
187    */
188   void *proc_cls;
189
190   /**
191    * The name to look up
192    */
193   char *name;
194
195   /**
196    * The subsystem set from REST
197    */
198   char *subsys;
199
200   /**
201    * The url
202    */
203   char *url;
204
205   /**
206    * The data from the REST request
207    */
208   const char* data;
209
210   /**
211    * the length of the REST data
212    */
213   size_t data_size;
214
215   /**
216    * HTTP method
217    */
218   const char* method;
219
220   /**
221    * Error response message
222    */
223   char *emsg;
224
225 };
226
227
228 /**
229  * Cleanup lookup handle
230  * @param handle Handle to clean up
231  */
232 static void
233 cleanup_handle (struct RequestHandle *handle)
234 {
235   struct EgoEntry *ego_entry;
236   struct EgoEntry *ego_tmp;
237   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
238               "Cleaning up\n");
239   if (NULL != handle->name)
240     GNUNET_free (handle->name);
241   if (NULL != handle->timeout_task)
242   {
243     GNUNET_SCHEDULER_cancel (handle->timeout_task);
244     handle->timeout_task = NULL;
245   }
246   if (NULL != handle->identity_handle)
247     GNUNET_IDENTITY_disconnect (handle->identity_handle);
248   if (NULL != handle->subsys)
249     GNUNET_free (handle->subsys);
250   if (NULL != handle->url)
251     GNUNET_free (handle->url);
252   if (NULL != handle->emsg)
253     GNUNET_free (handle->emsg);
254   for (ego_entry = handle->ego_head;
255        NULL != ego_entry;)
256   {
257     ego_tmp = ego_entry;
258     ego_entry = ego_entry->next;
259     GNUNET_free (ego_tmp->identifier);
260     GNUNET_free (ego_tmp->keystring);
261     GNUNET_free (ego_tmp);
262   }
263   GNUNET_free (handle);
264 }
265
266
267 /**
268  * Task run on errors.  Reports an error and cleans up everything.
269  *
270  * @param cls the `struct RequestHandle`
271  */
272 static void
273 do_error (void *cls)
274 {
275   struct RequestHandle *handle = cls;
276   struct MHD_Response *resp;
277   char *json_error;
278
279   if (NULL == handle->emsg)
280     handle->emsg = GNUNET_strdup("Unknown Error");
281
282   GNUNET_asprintf (&json_error, "{\"error\": \"%s\"}", handle->emsg);
283   handle->response_code = MHD_HTTP_OK;
284
285   resp = GNUNET_REST_create_response (json_error);
286   handle->proc (handle->proc_cls, resp, handle->response_code);
287   cleanup_handle (handle);
288   GNUNET_free(json_error);
289 }
290
291
292 /**
293  * Callback for IDENTITY_get()
294  *
295  * @param cls the RequestHandle
296  * @param ego the Ego found
297  * @param ctx the context
298  * @param name the id of the ego
299  */
300 static void
301 get_ego_for_subsys (void *cls,
302                     struct GNUNET_IDENTITY_Ego *ego,
303                     void **ctx,
304                     const char *name)
305 {
306   struct RequestHandle *handle = cls;
307   struct EgoEntry *ego_entry;
308   struct MHD_Response *resp;
309   json_t *json_root;
310   json_t *json_ego;
311   json_t *name_json;
312   char *result_str;
313   size_t index;
314
315   json_root = json_array();
316
317   for (ego_entry = handle->ego_head;
318        NULL != ego_entry;
319        ego_entry = ego_entry->next)
320   {
321     if ( (NULL != name) && (0 != strcmp (name, ego_entry->identifier)) )
322       continue;
323     if (NULL == name)
324       continue;
325
326     json_ego = json_object();
327     name_json = json_string (ego_entry->identifier);
328     json_object_set_new(json_ego, GNUNET_REST_JSON_IDENTITY_EGO, name_json);
329     json_array_append(json_root, json_ego);
330
331     break;
332   }
333
334   if (0 == json_array_size(json_root))
335   {
336     json_decref(json_root);
337     handle->emsg = GNUNET_strdup("No identity matches results!");
338     GNUNET_SCHEDULER_add_now (&do_error, handle);
339     return;
340   }
341
342   result_str = json_dumps(json_root, 0);
343   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
344   resp = GNUNET_REST_create_response (result_str);
345
346   json_array_foreach(json_root, index, json_ego )
347   {
348     json_decref(json_ego);
349   }
350   json_decref (json_root);
351   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
352   GNUNET_free (result_str);
353   cleanup_handle (handle);
354 }
355
356
357 /**
358  * Create a response with requested ego(s)
359  *
360  * @param con the Rest handle
361  * @param url the requested url
362  * @param cls the request handle
363  */
364 static void
365 ego_info_response (struct GNUNET_REST_RequestHandle *con,
366                    const char *url,
367                    void *cls)
368 {
369   const char *egoname;
370   char *result_str;
371   char *subsys_val;
372   char *keystring;
373   struct RequestHandle *handle = cls;
374   struct EgoEntry *ego_entry;
375   struct GNUNET_HashCode key;
376   struct MHD_Response *resp;
377   json_t *json_root;
378   json_t *json_ego;
379   json_t *name_str;
380   size_t index;
381
382   if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url, GNUNET_REST_API_NS_IDENTITY))
383   {
384     resp = GNUNET_REST_create_response (NULL);
385     handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
386     cleanup_handle (handle);
387     return;
388   }
389   egoname = NULL;
390   keystring = NULL;
391   if (strlen (GNUNET_REST_API_NS_IDENTITY) < strlen (handle->url))
392   {
393     keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY)+1];
394     //Return all egos
395     for (ego_entry = handle->ego_head;
396          NULL != ego_entry;
397          ego_entry = ego_entry->next)
398     {
399       if ( (NULL != keystring) && (0 != strcmp (keystring, ego_entry->keystring)) )
400         continue;
401       egoname = ego_entry->identifier;
402     }
403   }
404
405   if ( NULL == egoname ) {
406     GNUNET_CRYPTO_hash (GNUNET_REST_JSON_IDENTITY_SUBSYSTEM,
407                         strlen (GNUNET_REST_JSON_IDENTITY_SUBSYSTEM),
408                         &key);
409     if ( GNUNET_YES ==
410          GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
411                                                  &key) )
412     {
413       subsys_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
414                                                       &key);
415       if (NULL != subsys_val)
416       {
417         GNUNET_asprintf (&handle->subsys, "%s", subsys_val);
418         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsys_val);
419         handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
420                                           handle->subsys,
421                                           &get_ego_for_subsys,
422                                           handle);
423         return;
424       }
425     }
426   }
427
428   json_root = json_array();
429
430   //Return all egos
431   for (ego_entry = handle->ego_head;
432        NULL != ego_entry;
433        ego_entry = ego_entry->next)
434   {
435     if ( (NULL != egoname) && (0 != strcmp (egoname, ego_entry->identifier)) )
436       continue;
437
438     json_ego = json_object();
439
440     json_object_set_new( json_ego, "id", json_string (ego_entry->keystring));
441     json_object_set_new( json_ego, "type", json_string (GNUNET_REST_JSON_IDENTITY_EGO));
442     name_str = json_string (ego_entry->identifier);
443     json_object_set_new( json_ego, "name", name_str);
444
445     json_array_append( json_root, json_ego );
446   }
447
448   if ((size_t)0 == json_array_size(json_root))
449   {
450     json_decref (json_root);
451     handle->emsg = GNUNET_strdup ("No identities found!");
452     GNUNET_SCHEDULER_add_now (&do_error, handle);
453     return;
454   }
455
456   result_str = json_dumps(json_root, 0);
457   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
458   resp = GNUNET_REST_create_response (result_str);
459
460   //delete json_objects in json_array with macro
461   json_array_foreach(json_root, index, json_ego )
462   {
463     json_decref(json_ego);
464   }
465   json_decref (json_root);
466   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
467   GNUNET_free (result_str);
468   cleanup_handle (handle);
469 }
470
471 /**
472  * Processing finished
473  *
474  * @param cls request handle
475  * @param emsg error message
476  */
477 static void
478 do_finished (void *cls, const char *emsg)
479 {
480   struct RequestHandle *handle = cls;
481   struct MHD_Response *resp;
482
483   handle->op = NULL;
484   if (NULL != emsg)
485   {
486     handle->emsg = GNUNET_strdup (emsg);
487     GNUNET_SCHEDULER_add_now (&do_error, handle);
488     return;
489   }
490   resp = GNUNET_REST_create_response (NULL);
491   handle->proc (handle->proc_cls, resp, handle->response_code);
492   cleanup_handle (handle);
493 }
494
495 /**
496  * Create a new ego
497  *
498  * @param con rest handle
499  * @param url url
500  * @param cls request handle
501  */
502 static void
503 ego_create_cont (struct GNUNET_REST_RequestHandle *con,
504                  const char *url,
505                  void *cls)
506 {
507   struct RequestHandle *handle = cls;
508   struct EgoEntry *ego_entry;
509   struct MHD_Response *resp;
510   json_t *egoname_json;
511   json_t *data_js;
512   json_error_t err;
513   const char* egoname;
514   char term_data[handle->data_size+1];
515
516   if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
517   {
518     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
519     GNUNET_SCHEDULER_add_now (&do_error, handle);
520     return;
521   }
522
523   if (0 >= handle->data_size)
524   {
525     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
526     GNUNET_SCHEDULER_add_now (&do_error, handle);
527     return;
528   }
529   term_data[handle->data_size] = '\0';
530   GNUNET_memcpy (term_data, handle->data, handle->data_size);
531   data_js = json_loads (term_data,
532                         JSON_DECODE_ANY,
533                         &err);
534
535
536   if (NULL == data_js)
537   {
538     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
539     GNUNET_SCHEDULER_add_now (&do_error, handle);
540     return;
541   }
542   //instead of parse
543   if (!json_is_object(data_js))
544   {
545     json_decref(data_js);
546     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
547     GNUNET_SCHEDULER_add_now (&do_error, handle);
548     return;
549   }
550
551   if (1 != json_object_size (data_js))
552   {
553     json_decref (data_js);
554     handle->emsg = GNUNET_strdup("Provided resource count invalid");
555     GNUNET_SCHEDULER_add_now (&do_error, handle);
556     return;
557   }
558
559   egoname_json = json_object_get (data_js, GNUNET_REST_JSON_IDENTITY_NAME);
560   if (!json_is_string (egoname_json))
561   {
562     json_decref (data_js);
563     handle->emsg = GNUNET_strdup ("No name provided");
564     GNUNET_SCHEDULER_add_now (&do_error, handle);
565     return;
566   }
567   egoname = json_string_value (egoname_json);
568   if(0 >= strlen(egoname))
569   {
570     json_decref (data_js);
571     handle->emsg = GNUNET_strdup ("No name provided");
572     GNUNET_SCHEDULER_add_now (&do_error, handle);
573     return;
574   }
575   for (ego_entry = handle->ego_head;
576        NULL != ego_entry;
577        ego_entry = ego_entry->next)
578   {
579     if (0 == strcasecmp (egoname, ego_entry->identifier))
580     {
581       json_decref (data_js);
582       resp = GNUNET_REST_create_response (NULL);
583       handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
584       cleanup_handle (handle);
585       return;
586     }
587   }
588   GNUNET_asprintf (&handle->name, "%s", egoname);
589   json_decref (data_js);
590   handle->response_code = MHD_HTTP_CREATED;
591   handle->op = GNUNET_IDENTITY_create (handle->identity_handle,
592                                        handle->name,
593                                        &do_finished,
594                                        handle);
595 }
596
597
598 /**
599  * Handle ego edit request
600  *
601  * @param con rest connection handle
602  * @param url the url that is requested
603  * @param cls the RequestHandle
604  */
605 static void
606 ego_edit_cont (struct GNUNET_REST_RequestHandle *con,
607                const char *url,
608                void *cls)
609 {
610   struct RequestHandle *handle = cls;
611   struct EgoEntry *ego_entry;
612   struct EgoEntry *ego_entry_tmp;
613   struct MHD_Response *resp;
614   json_t *subsys_json;
615   json_t *name_json;
616   json_t *data_js;
617   json_error_t err;
618   const char *keystring;
619   const char *subsys;
620   const char *newname;
621   char term_data[handle->data_size+1];
622   int ego_exists = GNUNET_NO;
623
624   if (strlen (GNUNET_REST_API_NS_IDENTITY) > strlen (handle->url))
625   {
626     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
627     GNUNET_SCHEDULER_add_now (&do_error, handle);
628     return;
629   }
630
631   keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
632
633   for (ego_entry = handle->ego_head;
634        NULL != ego_entry;
635        ego_entry = ego_entry->next)
636   {
637     if (0 != strcasecmp (keystring, ego_entry->keystring))
638       continue;
639     ego_exists = GNUNET_YES;
640     break;
641   }
642
643   if (GNUNET_NO == ego_exists)
644   {
645     resp = GNUNET_REST_create_response (NULL);
646     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
647     cleanup_handle (handle);
648     return;
649   }
650
651   if (0 >= handle->data_size)
652   {
653     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
654     GNUNET_SCHEDULER_add_now (&do_error, handle);
655     return;
656   }
657
658   term_data[handle->data_size] = '\0';
659   GNUNET_memcpy (term_data, handle->data, handle->data_size);
660   data_js = json_loads (term_data,
661                         JSON_DECODE_ANY,
662                         &err);
663   if (NULL == data_js)
664   {
665     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
666     GNUNET_SCHEDULER_add_now (&do_error, handle);
667     return;
668   }
669   if (!json_is_object(data_js))
670   {
671     json_decref (data_js);
672     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
673     GNUNET_SCHEDULER_add_now (&do_error, handle);
674     return;
675   }
676
677   if (1 != json_object_size(data_js))
678   {
679     json_decref (data_js);
680     handle->emsg = GNUNET_strdup ("Resource amount invalid");
681     GNUNET_SCHEDULER_add_now (&do_error, handle);
682     return;
683   }
684
685   //This is a rename
686   name_json = json_object_get (data_js, GNUNET_REST_JSON_IDENTITY_NEWNAME);
687   if ((NULL != name_json) && json_is_string (name_json))
688   {
689     newname = json_string_value (name_json);
690     if(0 >= strlen(newname))
691     {
692       json_decref (data_js);
693       handle->emsg = GNUNET_strdup ("No name provided");
694       GNUNET_SCHEDULER_add_now (&do_error, handle);
695       return;
696     }
697     for (ego_entry_tmp = handle->ego_head;
698          NULL != ego_entry_tmp;
699          ego_entry_tmp = ego_entry_tmp->next)
700     {
701       if (0 == strcasecmp (newname, ego_entry_tmp->identifier) &&
702           0 != strcasecmp (keystring, ego_entry_tmp->keystring))
703       {
704         //Ego with same name not allowed
705         json_decref (data_js);
706         resp = GNUNET_REST_create_response (NULL);
707         handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
708         cleanup_handle (handle);
709         return;
710       }
711     }
712     handle->response_code = MHD_HTTP_NO_CONTENT;
713     handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
714                                          ego_entry->identifier,
715                                          newname,
716                                          &do_finished,
717                                          handle);
718     json_decref (data_js);
719     return;
720   }
721
722   //Set subsystem
723   subsys_json = json_object_get (data_js, GNUNET_REST_JSON_IDENTITY_SUBSYSTEM);
724   if ( (NULL != subsys_json) && json_is_string (subsys_json))
725   {
726     subsys = json_string_value (subsys_json);
727     if(0 >= strlen(subsys))
728     {
729       json_decref (data_js);
730       handle->emsg = GNUNET_strdup ("No name provided");
731       GNUNET_SCHEDULER_add_now (&do_error, handle);
732       return;
733     }
734     GNUNET_asprintf (&handle->subsys, "%s", subsys);
735     json_decref (data_js);
736     handle->response_code = MHD_HTTP_NO_CONTENT;
737     handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
738                                       handle->subsys,
739                                       ego_entry->ego,
740                                       &do_finished,
741                                       handle);
742     return;
743   }
744   json_decref (data_js);
745   handle->emsg = GNUNET_strdup ("Subsystem not provided");
746   GNUNET_SCHEDULER_add_now (&do_error, handle);
747 }
748
749 /**
750  * Handle ego delete request
751  *
752  * @param con_handle the connection handle
753  * @param url the url
754  * @param cls the RequestHandle
755  */
756 void
757 ego_delete_cont (struct GNUNET_REST_RequestHandle *con_handle,
758                  const char* url,
759                  void *cls)
760 {
761   const char *keystring;
762   struct EgoEntry *ego_entry;
763   struct MHD_Response *resp;
764   struct RequestHandle *handle = cls;
765   int ego_exists = GNUNET_NO;
766
767   if (strlen (GNUNET_REST_API_NS_IDENTITY) >= strlen (handle->url))
768   {
769     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
770     GNUNET_SCHEDULER_add_now (&do_error, handle);
771     return;
772   }
773
774   keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
775   for (ego_entry = handle->ego_head;
776        NULL != ego_entry;
777        ego_entry = ego_entry->next)
778   {
779     if (0 != strcasecmp (keystring, ego_entry->keystring))
780       continue;
781     ego_exists = GNUNET_YES;
782     break;
783   }
784   if (GNUNET_NO == ego_exists)
785   {
786     resp = GNUNET_REST_create_response (NULL);
787     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
788     cleanup_handle (handle);
789     return;
790   }
791   handle->response_code = MHD_HTTP_NO_CONTENT;
792   handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
793                                        ego_entry->identifier,
794                                        &do_finished,
795                                        handle);
796
797 }
798
799
800 /**
801  * Respond to OPTIONS request
802  *
803  * @param con_handle the connection handle
804  * @param url the url
805  * @param cls the RequestHandle
806  */
807 static void
808 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
809               const char* url,
810               void *cls)
811 {
812   struct MHD_Response *resp;
813   struct RequestHandle *handle = cls;
814
815   //For now, independent of path return all options
816   resp = GNUNET_REST_create_response (NULL);
817   MHD_add_response_header (resp,
818                            "Access-Control-Allow-Methods",
819                            allow_methods);
820   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
821   cleanup_handle (handle);
822   return;
823 }
824
825 /**
826  * Handle rest request
827  *
828  * @param handle the request handle
829  */
830 static void
831 init_cont (struct RequestHandle *handle)
832 {
833   struct GNUNET_REST_RequestHandlerError err;
834   static const struct GNUNET_REST_RequestHandler handlers[] = {
835     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_info_response},
836     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create_cont},
837     {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY, &ego_edit_cont},
838     {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY, &ego_delete_cont},
839     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont},
840     GNUNET_REST_HANDLER_END
841   };
842
843   if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle,
844                                                   handlers,
845                                                   &err,
846                                                   handle))
847   {
848     handle->response_code = err.error_code;
849     GNUNET_SCHEDULER_add_now (&do_error, handle);
850   }
851 }
852
853 /**
854  * If listing is enabled, prints information about the egos.
855  *
856  * This function is initially called for all egos and then again
857  * whenever a ego's identifier changes or if it is deleted.  At the
858  * end of the initial pass over all egos, the function is once called
859  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
860  * be invoked in the future or that there was an error.
861  *
862  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
863  * this function is only called ONCE, and 'NULL' being passed in
864  * 'ego' does indicate an error (i.e. name is taken or no default
865  * value is known).  If 'ego' is non-NULL and if '*ctx'
866  * is set in those callbacks, the value WILL be passed to a subsequent
867  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
868  * that one was not NULL).
869  *
870  * When an identity is renamed, this function is called with the
871  * (known) ego but the NEW identifier.
872  *
873  * When an identity is deleted, this function is called with the
874  * (known) ego and "NULL" for the 'identifier'.  In this case,
875  * the 'ego' is henceforth invalid (and the 'ctx' should also be
876  * cleaned up).
877  *
878  * @param cls closure
879  * @param ego ego handle
880  * @param ctx context for application to store data for this ego
881  *                 (during the lifetime of this process, initially NULL)
882  * @param identifier identifier assigned by the user for this ego,
883  *                   NULL if the user just deleted the ego and it
884  *                   must thus no longer be used
885  */
886 static void
887 list_ego (void *cls,
888           struct GNUNET_IDENTITY_Ego *ego,
889           void **ctx,
890           const char *identifier)
891 {
892   struct RequestHandle *handle = cls;
893   struct EgoEntry *ego_entry;
894   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
895
896   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
897   {
898     handle->state = ID_REST_STATE_POST_INIT;
899     init_cont (handle);
900     return;
901   }
902   if (ID_REST_STATE_INIT == handle->state) {
903     ego_entry = GNUNET_new (struct EgoEntry);
904     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
905     ego_entry->keystring =
906       GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
907     ego_entry->ego = ego;
908     GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
909     GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
910   }
911
912 }
913
914 /**
915  * Function processing the REST call
916  *
917  * @param method HTTP method
918  * @param url URL of the HTTP request
919  * @param data body of the HTTP request (optional)
920  * @param data_size length of the body
921  * @param proc callback function for the result
922  * @param proc_cls closure for callback function
923  * @return GNUNET_OK if request accepted
924  */
925 static void
926 rest_identity_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
927                               GNUNET_REST_ResultProcessor proc,
928                               void *proc_cls)
929 {
930   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
931
932
933
934   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
935   handle->response_code = MHD_HTTP_OK;
936   handle->proc_cls = proc_cls;
937   handle->proc = proc;
938   handle->state = ID_REST_STATE_INIT;
939   handle->conndata_handle = conndata_handle;
940   handle->data = conndata_handle->data;
941   handle->data_size = conndata_handle->data_size;
942   handle->method = conndata_handle->method;
943   GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
944   if (handle->url[strlen (handle->url)-1] == '/')
945     handle->url[strlen (handle->url)-1] = '\0';
946   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
947               "Connecting...\n");
948   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
949                                                      &list_ego,
950                                                      handle);
951   handle->timeout_task =
952     GNUNET_SCHEDULER_add_delayed (handle->timeout,
953                                   &do_error,
954                                   handle);
955
956
957   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
958               "Connected\n");
959 }
960
961 /**
962  * Entry point for the plugin.
963  *
964  * @param cls Config info
965  * @return NULL on error, otherwise the plugin context
966  */
967 void *
968 libgnunet_plugin_rest_identity_init (void *cls)
969 {
970   static struct Plugin plugin;
971   struct GNUNET_REST_Plugin *api;
972
973   cfg = cls;
974   if (NULL != plugin.cfg)
975     return NULL;                /* can only initialize once! */
976   memset (&plugin, 0, sizeof (struct Plugin));
977   plugin.cfg = cfg;
978   api = GNUNET_new (struct GNUNET_REST_Plugin);
979   api->cls = &plugin;
980   api->name = GNUNET_REST_API_NS_IDENTITY;
981   api->process_request = &rest_identity_process_request;
982   GNUNET_asprintf (&allow_methods,
983                    "%s, %s, %s, %s, %s",
984                    MHD_HTTP_METHOD_GET,
985                    MHD_HTTP_METHOD_POST,
986                    MHD_HTTP_METHOD_PUT,
987                    MHD_HTTP_METHOD_DELETE,
988                    MHD_HTTP_METHOD_OPTIONS);
989
990   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
991               _("Identity REST API initialized\n"));
992   return api;
993 }
994
995
996 /**
997  * Exit point from the plugin.
998  *
999  * @param cls the plugin context (as returned by "init")
1000  * @return always NULL
1001  */
1002 void *
1003 libgnunet_plugin_rest_identity_done (void *cls)
1004 {
1005   struct GNUNET_REST_Plugin *api = cls;
1006   struct Plugin *plugin = api->cls;
1007
1008   plugin->cfg = NULL;
1009   GNUNET_free_non_null (allow_methods);
1010   GNUNET_free (api);
1011   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1012               "Identity REST plugin is finished\n");
1013   return NULL;
1014 }
1015
1016 /* end of plugin_rest_gns.c */