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