even more .gitignore updates
[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     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
431                 "Egoname: %s\n",
432                 ego_entry->identifier);
433     name_str = json_string (ego_entry->identifier);
434     GNUNET_JSONAPI_resource_add_attr (
435                                            json_resource,
436                                            GNUNET_REST_JSONAPI_IDENTITY_NAME,
437                                            name_str);
438     json_decref (name_str);
439     GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
440   }
441   if (0 == GNUNET_JSONAPI_document_resource_count (json_document))
442   {
443     GNUNET_JSONAPI_document_delete (json_document);
444     handle->emsg = GNUNET_strdup ("No identities found!");
445     GNUNET_SCHEDULER_add_now (&do_error, handle);
446     return;
447   }
448   GNUNET_JSONAPI_document_serialize (json_document, &result_str);
449   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
450   resp = GNUNET_REST_create_response (result_str);
451   GNUNET_JSONAPI_document_delete (json_document);
452   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
453   GNUNET_free (result_str);
454   cleanup_handle (handle);
455 }
456
457 /**
458  * Processing finished
459  *
460  * @param cls request handle
461  * @param emsg error message
462  */
463 static void
464 do_finished (void *cls, const char *emsg)
465 {
466   struct RequestHandle *handle = cls;
467   struct MHD_Response *resp;
468
469   handle->op = NULL;
470   if (NULL != emsg)
471   {
472     handle->emsg = GNUNET_strdup (emsg);
473     GNUNET_SCHEDULER_add_now (&do_error, handle);
474     return;
475   }
476   resp = GNUNET_REST_create_response (NULL);
477   handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
478   cleanup_handle (handle);
479 }
480
481 /**
482  * Create a new ego
483  *
484  * @param con rest handle
485  * @param url url
486  * @param cls request handle
487  */
488 static void
489 ego_create_cont (struct GNUNET_REST_RequestHandle *con,
490                  const char *url,
491                  void *cls)
492 {
493   struct RequestHandle *handle = cls;
494   struct EgoEntry *ego_entry;
495   struct MHD_Response *resp;
496   struct GNUNET_JSONAPI_Document *json_obj;
497   struct GNUNET_JSONAPI_Resource *json_res;
498   json_t *egoname_json;
499   json_t *data_js;
500   json_error_t err;
501   const char* egoname;
502   char term_data[handle->data_size+1];
503   struct GNUNET_JSON_Specification docspec[] = {
504     GNUNET_JSON_spec_jsonapi_document (&json_obj),
505     GNUNET_JSON_spec_end()
506   };
507   if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
508   {
509     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
510     GNUNET_SCHEDULER_add_now (&do_error, handle);
511     return;
512   }
513   if (0 >= handle->data_size)
514   {
515     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
516     GNUNET_SCHEDULER_add_now (&do_error, handle);
517     return;
518   }
519   term_data[handle->data_size] = '\0';
520   GNUNET_memcpy (term_data, handle->data, handle->data_size);
521   data_js = json_loads (term_data,
522                         JSON_DECODE_ANY,
523                         &err);
524   GNUNET_assert (NULL != data_js);
525   GNUNET_assert (GNUNET_OK ==
526                  GNUNET_JSON_parse (data_js, docspec,
527                                     NULL, NULL));
528
529   json_decref (data_js);
530
531   if (NULL == json_obj)
532   {
533     GNUNET_SCHEDULER_add_now (&do_error, handle);
534     return;
535   }
536   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
537   {
538     GNUNET_JSONAPI_document_delete (json_obj);
539     handle->emsg = GNUNET_strdup ("Provided resource count invalid");
540     GNUNET_SCHEDULER_add_now (&do_error, handle);
541     return;
542   }
543   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
544   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO))
545   {
546     GNUNET_JSONAPI_document_delete (json_obj);
547     resp = GNUNET_REST_create_response (NULL);
548     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
549     cleanup_handle (handle);
550     return;
551   }
552   egoname_json = GNUNET_JSONAPI_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_NAME);
553   if (!json_is_string (egoname_json))
554   {
555     GNUNET_JSONAPI_document_delete (json_obj);
556     handle->emsg = GNUNET_strdup ("No name provided");
557     GNUNET_SCHEDULER_add_now (&do_error, handle);
558     return;
559   }
560   egoname = json_string_value (egoname_json);
561   for (ego_entry = handle->ego_head;
562        NULL != ego_entry;
563        ego_entry = ego_entry->next)
564   {
565     if (0 == strcasecmp (egoname, ego_entry->identifier))
566     {
567       GNUNET_JSONAPI_document_delete (json_obj);
568       resp = GNUNET_REST_create_response (NULL);
569       handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
570       cleanup_handle (handle);
571       return;
572     }
573   }
574   GNUNET_asprintf (&handle->name, "%s", egoname);
575   GNUNET_JSONAPI_document_delete (json_obj);
576   handle->op = GNUNET_IDENTITY_create (handle->identity_handle,
577                                        handle->name,
578                                        &do_finished,
579                                        handle);
580 }
581
582
583 /**
584  * Handle ego edit request
585  *
586  * @param con rest connection handle
587  * @param url the url that is requested
588  * @param cls the RequestHandle
589  */
590 static void
591 ego_edit_cont (struct GNUNET_REST_RequestHandle *con,
592                const char *url,
593                void *cls)
594 {
595   struct GNUNET_JSONAPI_Document *json_obj;
596   struct GNUNET_JSONAPI_Resource *json_res;
597   struct RequestHandle *handle = cls;
598   struct EgoEntry *ego_entry;
599   struct MHD_Response *resp;
600   json_t *subsys_json;
601   json_t *name_json;
602   json_t *data_js;
603   json_error_t err;
604   const char *keystring;
605   const char *subsys;
606   const char *newname;
607   char term_data[handle->data_size+1];
608   int ego_exists = GNUNET_NO;
609   struct GNUNET_JSON_Specification docspec[] = {
610     GNUNET_JSON_spec_jsonapi_document (&json_obj),
611     GNUNET_JSON_spec_end()
612   };
613
614   if (strlen (GNUNET_REST_API_NS_IDENTITY) > strlen (handle->url))
615   {
616     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
617     GNUNET_SCHEDULER_add_now (&do_error, handle);
618     return;
619   }
620
621   keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
622
623   for (ego_entry = handle->ego_head;
624        NULL != ego_entry;
625        ego_entry = ego_entry->next)
626   {
627     if (0 != strcasecmp (keystring, ego_entry->keystring))
628       continue;
629     ego_exists = GNUNET_YES;
630     break;
631   }
632
633   if (GNUNET_NO == ego_exists)
634   {
635     resp = GNUNET_REST_create_response (NULL);
636     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
637     cleanup_handle (handle);
638     return;
639   }
640
641   if (0 >= handle->data_size)
642   {
643     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
644     GNUNET_SCHEDULER_add_now (&do_error, handle);
645     return;
646   }
647
648   term_data[handle->data_size] = '\0';
649   GNUNET_memcpy (term_data, handle->data, handle->data_size);
650   data_js = json_loads (term_data,
651                         JSON_DECODE_ANY,
652                         &err);
653   GNUNET_assert (NULL != data_js);
654   GNUNET_assert (GNUNET_OK ==
655                  GNUNET_JSON_parse (data_js, docspec,
656                                     NULL, NULL));
657
658   json_decref (data_js);
659
660   if (NULL == json_obj)
661   {
662     handle->emsg = GNUNET_strdup ("Data invalid");
663     GNUNET_SCHEDULER_add_now (&do_error, handle);
664     return;
665   }
666
667   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
668   {
669     GNUNET_JSONAPI_document_delete (json_obj);
670     handle->emsg = GNUNET_strdup ("Resource amount invalid");
671     GNUNET_SCHEDULER_add_now (&do_error, handle);
672     return;
673   }
674   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
675
676   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO))
677   {
678     GNUNET_JSONAPI_document_delete (json_obj);
679     handle->emsg = GNUNET_strdup ("Resource type invalid");
680     GNUNET_SCHEDULER_add_now (&do_error, handle);
681     return;
682   }
683
684   //This is a rename
685   name_json = GNUNET_JSONAPI_resource_read_attr (json_res,
686                                                  GNUNET_REST_JSONAPI_IDENTITY_NEWNAME);
687   if ((NULL != name_json) && json_is_string (name_json))
688   {
689     newname = json_string_value (name_json);
690     for (ego_entry = handle->ego_head;
691          NULL != ego_entry;
692          ego_entry = ego_entry->next)
693     {
694       if (0 == strcasecmp (newname, ego_entry->identifier) &&
695           0 != strcasecmp (keystring, ego_entry->keystring))
696       {
697         //Ego with same name not allowed
698         GNUNET_JSONAPI_document_delete (json_obj);
699         resp = GNUNET_REST_create_response (NULL);
700         handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
701         cleanup_handle (handle);
702         return;
703       }
704     }
705     handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
706                                          ego_entry->identifier,
707                                          newname,
708                                          &do_finished,
709                                          handle);
710     GNUNET_JSONAPI_document_delete (json_obj);
711     return;
712   }
713
714   //Set subsystem
715   subsys_json = GNUNET_JSONAPI_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM);
716   if ( (NULL != subsys_json) && json_is_string (subsys_json))
717   {
718     subsys = json_string_value (subsys_json);
719     GNUNET_asprintf (&handle->subsys, "%s", subsys);
720     GNUNET_JSONAPI_document_delete (json_obj);
721     handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
722                                       handle->subsys,
723                                       ego_entry->ego,
724                                       &do_finished,
725                                       handle);
726     return;
727   }
728   GNUNET_JSONAPI_document_delete (json_obj);
729   handle->emsg = GNUNET_strdup ("Subsystem not provided");
730   GNUNET_SCHEDULER_add_now (&do_error, handle);
731 }
732
733 void
734 ego_delete_cont (struct GNUNET_REST_RequestHandle *con_handle,
735                  const char* url,
736                  void *cls)
737 {
738   const char *keystring;
739   struct EgoEntry *ego_entry;
740   struct MHD_Response *resp;
741   struct RequestHandle *handle = cls;
742   int ego_exists = GNUNET_NO;
743
744   if (strlen (GNUNET_REST_API_NS_IDENTITY) >= strlen (handle->url))
745   {
746     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
747     GNUNET_SCHEDULER_add_now (&do_error, handle);
748     return;
749   }
750
751   keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
752   for (ego_entry = handle->ego_head;
753        NULL != ego_entry;
754        ego_entry = ego_entry->next)
755   {
756     if (0 != strcasecmp (keystring, ego_entry->keystring))
757       continue;
758     ego_exists = GNUNET_YES;
759     break;
760   }
761   if (GNUNET_NO == ego_exists)
762   {
763     resp = GNUNET_REST_create_response (NULL);
764     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
765     cleanup_handle (handle);
766     return;
767   }
768   handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
769                                        ego_entry->identifier,
770                                        &do_finished,
771                                        handle);
772
773 }
774
775
776 /**
777  * Respond to OPTIONS request
778  *
779  * @param con_handle the connection handle
780  * @param url the url
781  * @param cls the RequestHandle
782  */
783 static void
784 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
785               const char* url,
786               void *cls)
787 {
788   struct MHD_Response *resp;
789   struct RequestHandle *handle = cls;
790
791   //For now, independent of path return all options
792   resp = GNUNET_REST_create_response (NULL);
793   MHD_add_response_header (resp,
794                            "Access-Control-Allow-Methods",
795                            allow_methods);
796   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
797   cleanup_handle (handle);
798   return;
799 }
800
801 /**
802  * Handle rest request
803  *
804  * @param handle the request handle
805  */
806 static void
807 init_cont (struct RequestHandle *handle)
808 {
809   struct GNUNET_REST_RequestHandlerError err;
810   static const struct GNUNET_REST_RequestHandler handlers[] = {
811     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_info_response},
812     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create_cont},
813     {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY, &ego_edit_cont},
814     {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY, &ego_delete_cont},
815     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont},
816     GNUNET_REST_HANDLER_END
817   };
818
819   if (GNUNET_NO == GNUNET_JSONAPI_handle_request (handle->conndata_handle,
820                                                   handlers,
821                                                   &err,
822                                                   handle))
823   {
824     handle->response_code = err.error_code;
825     GNUNET_SCHEDULER_add_now (&do_error, handle);
826   }
827 }
828
829 /**
830  * If listing is enabled, prints information about the egos.
831  *
832  * This function is initially called for all egos and then again
833  * whenever a ego's identifier changes or if it is deleted.  At the
834  * end of the initial pass over all egos, the function is once called
835  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
836  * be invoked in the future or that there was an error.
837  *
838  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
839  * this function is only called ONCE, and 'NULL' being passed in
840  * 'ego' does indicate an error (i.e. name is taken or no default
841  * value is known).  If 'ego' is non-NULL and if '*ctx'
842  * is set in those callbacks, the value WILL be passed to a subsequent
843  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
844  * that one was not NULL).
845  *
846  * When an identity is renamed, this function is called with the
847  * (known) ego but the NEW identifier.
848  *
849  * When an identity is deleted, this function is called with the
850  * (known) ego and "NULL" for the 'identifier'.  In this case,
851  * the 'ego' is henceforth invalid (and the 'ctx' should also be
852  * cleaned up).
853  *
854  * @param cls closure
855  * @param ego ego handle
856  * @param ctx context for application to store data for this ego
857  *                 (during the lifetime of this process, initially NULL)
858  * @param identifier identifier assigned by the user for this ego,
859  *                   NULL if the user just deleted the ego and it
860  *                   must thus no longer be used
861  */
862 static void
863 list_ego (void *cls,
864           struct GNUNET_IDENTITY_Ego *ego,
865           void **ctx,
866           const char *identifier)
867 {
868   struct RequestHandle *handle = cls;
869   struct EgoEntry *ego_entry;
870   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
871
872   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
873   {
874     handle->state = ID_REST_STATE_POST_INIT;
875     init_cont (handle);
876     return;
877   }
878   if (ID_REST_STATE_INIT == handle->state) {
879     ego_entry = GNUNET_new (struct EgoEntry);
880     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
881     ego_entry->keystring =
882       GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
883     ego_entry->ego = ego;
884     GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
885     GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
886   }
887
888 }
889
890 /**
891  * Function processing the REST call
892  *
893  * @param method HTTP method
894  * @param url URL of the HTTP request
895  * @param data body of the HTTP request (optional)
896  * @param data_size length of the body
897  * @param proc callback function for the result
898  * @param proc_cls closure for callback function
899  * @return GNUNET_OK if request accepted
900  */
901 static void
902 rest_identity_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
903                               GNUNET_REST_ResultProcessor proc,
904                               void *proc_cls)
905 {
906   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
907
908
909
910   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
911
912   handle->proc_cls = proc_cls;
913   handle->proc = proc;
914   handle->state = ID_REST_STATE_INIT;
915   handle->conndata_handle = conndata_handle;
916   handle->data = conndata_handle->data;
917   handle->data_size = conndata_handle->data_size;
918   handle->method = conndata_handle->method;
919   GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
920   if (handle->url[strlen (handle->url)-1] == '/')
921     handle->url[strlen (handle->url)-1] = '\0';
922   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
923               "Connecting...\n");
924   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
925                                                      &list_ego,
926                                                      handle);
927   handle->timeout_task =
928     GNUNET_SCHEDULER_add_delayed (handle->timeout,
929                                   &do_error,
930                                   handle);
931
932
933   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
934               "Connected\n");
935 }
936
937 /**
938  * Entry point for the plugin.
939  *
940  * @param cls Config info
941  * @return NULL on error, otherwise the plugin context
942  */
943 void *
944 libgnunet_plugin_rest_identity_init (void *cls)
945 {
946   static struct Plugin plugin;
947   struct GNUNET_REST_Plugin *api;
948
949   cfg = cls;
950   if (NULL != plugin.cfg)
951     return NULL;                /* can only initialize once! */
952   memset (&plugin, 0, sizeof (struct Plugin));
953   plugin.cfg = cfg;
954   api = GNUNET_new (struct GNUNET_REST_Plugin);
955   api->cls = &plugin;
956   api->name = GNUNET_REST_API_NS_IDENTITY;
957   api->process_request = &rest_identity_process_request;
958   GNUNET_asprintf (&allow_methods,
959                    "%s, %s, %s, %s, %s",
960                    MHD_HTTP_METHOD_GET,
961                    MHD_HTTP_METHOD_POST,
962                    MHD_HTTP_METHOD_PUT,
963                    MHD_HTTP_METHOD_DELETE,
964                    MHD_HTTP_METHOD_OPTIONS);
965
966   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
967               _("Identity REST API initialized\n"));
968   return api;
969 }
970
971
972 /**
973  * Exit point from the plugin.
974  *
975  * @param cls the plugin context (as returned by "init")
976  * @return always NULL
977  */
978 void *
979 libgnunet_plugin_rest_identity_done (void *cls)
980 {
981   struct GNUNET_REST_Plugin *api = cls;
982   struct Plugin *plugin = api->cls;
983
984   plugin->cfg = NULL;
985   GNUNET_free_non_null (allow_methods);
986   GNUNET_free (api);
987   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
988               "Identity REST plugin is finished\n");
989   return NULL;
990 }
991
992 /* end of plugin_rest_gns.c */