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