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