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