fix build; move rest plugins to separate folder
[oweals/gnunet.git] / src / rest-plugins / 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 it
6    under the terms of the GNU Affero General Public License as published
7    by the Free Software Foundation, either version 3 of the License,
8    or (at your 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    Affero General Public License for more details.
14
15    You should have received a copy of the GNU Affero General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 /**
19  * @author Martin Schanzenbach
20  * @author Philippe Buschmann
21  * @file identity/plugin_rest_identity.c
22  * @brief GNUnet Identity REST plugin
23  */
24
25 #include "platform.h"
26 #include "gnunet_rest_plugin.h"
27 #include "gnunet_identity_service.h"
28 #include "gnunet_rest_lib.h"
29 #include "microhttpd.h"
30 #include <jansson.h>
31
32 /**
33  * Identity Namespace
34  */
35 #define GNUNET_REST_API_NS_IDENTITY "/identity"
36
37 /**
38  * Identity Namespace with public key specifier
39  */
40 #define GNUNET_REST_API_NS_IDENTITY_ALL "/identity/all"
41
42 /**
43  * Identity Namespace with public key specifier
44  */
45 #define GNUNET_REST_API_NS_IDENTITY_PUBKEY "/identity/pubkey"
46
47 /**
48  * Identity Namespace with public key specifier
49  */
50 #define GNUNET_REST_API_NS_IDENTITY_NAME "/identity/name"
51
52 /**
53  * Identity Subsystem Namespace
54  */
55 #define GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM "/identity/subsystem"
56
57 /**
58  * Parameter public key
59  */
60 #define GNUNET_REST_IDENTITY_PARAM_PUBKEY "pubkey"
61
62 /**
63  * Parameter subsystem
64  */
65 #define GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM "subsystem"
66
67 /**
68  * Parameter name
69  */
70 #define GNUNET_REST_IDENTITY_PARAM_NAME "name"
71
72 /**
73  * Parameter new name
74  */
75 #define GNUNET_REST_IDENTITY_PARAM_NEWNAME "newname"
76
77 /**
78  * Error message Unknown Error
79  */
80 #define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error"
81
82 /**
83  * Error message No identity found
84  */
85 #define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found"
86
87 /**
88  * Error message Missing identity name
89  */
90 #define GNUNET_REST_IDENTITY_MISSING_NAME "Missing identity name"
91
92 /**
93  * Error message Missing identity name
94  */
95 #define GNUNET_REST_IDENTITY_MISSING_PUBKEY "Missing identity public key"
96
97 /**
98  * Error message No data
99  */
100 #define GNUNET_REST_ERROR_NO_DATA "No data"
101
102 /**
103  * Error message Data invalid
104  */
105 #define GNUNET_REST_ERROR_DATA_INVALID "Data invalid"
106
107 /**
108  * State while collecting all egos
109  */
110 #define ID_REST_STATE_INIT 0
111
112 /**
113  * Done collecting egos
114  */
115 #define ID_REST_STATE_POST_INIT 1
116
117 /**
118  * The configuration handle
119  */
120 const struct GNUNET_CONFIGURATION_Handle *cfg;
121
122 /**
123  * HTTP methods allows for this plugin
124  */
125 static char* allow_methods;
126
127 /**
128  * @brief struct returned by the initialization function of the plugin
129  */
130 struct Plugin
131 {
132   const struct GNUNET_CONFIGURATION_Handle *cfg;
133 };
134
135 /**
136  * The ego list
137  */
138 struct EgoEntry
139 {
140   /**
141    * DLL
142    */
143   struct EgoEntry *next;
144
145   /**
146    * DLL
147    */
148   struct EgoEntry *prev;
149
150   /**
151    * Ego Identifier
152    */
153   char *identifier;
154
155   /**
156    * Public key string
157    */
158   char *keystring;
159
160   /**
161    * The Ego
162    */
163   struct GNUNET_IDENTITY_Ego *ego;
164 };
165
166 /**
167  * The request handle
168  */
169 struct RequestHandle
170 {
171   /**
172    * The data from the REST request
173    */
174   const char* data;
175
176   /**
177    * The name to look up
178    */
179   char *name;
180
181   /**
182    * the length of the REST data
183    */
184   size_t data_size;
185
186
187   /**
188    * Ego list
189    */
190   struct EgoEntry *ego_head;
191
192   /**
193    * Ego list
194    */
195   struct EgoEntry *ego_tail;
196
197   /**
198    * The processing state
199    */
200   int state;
201
202   /**
203    * Handle to Identity service.
204    */
205   struct GNUNET_IDENTITY_Handle *identity_handle;
206
207   /**
208    * IDENTITY Operation
209    */
210   struct GNUNET_IDENTITY_Operation *op;
211
212   /**
213    * Rest connection
214    */
215   struct GNUNET_REST_RequestHandle *rest_handle;
216
217   /**
218    * Desired timeout for the lookup (default is no timeout).
219    */
220   struct GNUNET_TIME_Relative timeout;
221
222   /**
223    * ID of a task associated with the resolution process.
224    */
225   struct GNUNET_SCHEDULER_Task *timeout_task;
226
227   /**
228    * The plugin result processor
229    */
230   GNUNET_REST_ResultProcessor proc;
231
232   /**
233    * The closure of the result processor
234    */
235   void *proc_cls;
236
237   /**
238    * The url
239    */
240   char *url;
241
242   /**
243    * Error response message
244    */
245   char *emsg;
246
247   /**
248    * Response code
249    */
250   int response_code;
251
252 };
253
254 /**
255  * Cleanup lookup handle
256  * @param handle Handle to clean up
257  */
258 static void
259 cleanup_handle (void *cls)
260 {
261   struct RequestHandle *handle = cls;
262   struct EgoEntry *ego_entry;
263   struct EgoEntry *ego_tmp;
264
265   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
266   if (NULL != handle->timeout_task)
267   {
268     GNUNET_SCHEDULER_cancel (handle->timeout_task);
269     handle->timeout_task = NULL;
270   }
271
272   if (NULL != handle->url)
273     GNUNET_free(handle->url);
274   if (NULL != handle->emsg)
275     GNUNET_free(handle->emsg);
276   if (NULL != handle->name)
277     GNUNET_free (handle->name);
278   if (NULL != handle->identity_handle)
279     GNUNET_IDENTITY_disconnect (handle->identity_handle);
280
281   for (ego_entry = handle->ego_head;
282   NULL != ego_entry;)
283   {
284     ego_tmp = ego_entry;
285     ego_entry = ego_entry->next;
286     GNUNET_free(ego_tmp->identifier);
287     GNUNET_free(ego_tmp->keystring);
288     GNUNET_free(ego_tmp);
289   }
290
291   GNUNET_free(handle);
292 }
293
294 /**
295  * Task run on errors.  Reports an error and cleans up everything.
296  *
297  * @param cls the `struct RequestHandle`
298  */
299 static void
300 do_error (void *cls)
301 {
302   struct RequestHandle *handle = cls;
303   struct MHD_Response *resp;
304   json_t *json_error = json_object();
305   char *response;
306
307   if (NULL == handle->emsg)
308     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_ERROR_UNKNOWN);
309
310   json_object_set_new(json_error,"error", json_string(handle->emsg));
311
312   if (0 == handle->response_code)
313     handle->response_code = MHD_HTTP_OK;
314   response = json_dumps (json_error, 0);
315   resp = GNUNET_REST_create_response (response);
316   handle->proc (handle->proc_cls, resp, handle->response_code);
317   json_decref(json_error);
318   GNUNET_free(response);
319   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
320 }
321
322
323
324 /**
325  * Get EgoEntry from list with either a public key or a name
326  * If public key and name are not NULL, it returns the public key result first
327  *
328  * @param handle the RequestHandle
329  * @param pubkey the public key of an identity (only one can be NULL)
330  * @param name the name of an identity (only one can be NULL)
331  * @return EgoEntry or NULL if not found
332  */
333 struct EgoEntry*
334 get_egoentry(struct RequestHandle *handle, char* pubkey, char *name)
335 {
336   struct EgoEntry *ego_entry;
337   if (NULL != pubkey)
338   {
339     for (ego_entry = handle->ego_head;
340         NULL != ego_entry;
341         ego_entry = ego_entry->next)
342     {
343       if (0 != strcasecmp (pubkey, ego_entry->keystring))
344         continue;
345       return ego_entry;
346     }
347   }
348   if (NULL != name)
349   {
350     for (ego_entry = handle->ego_head;
351         NULL != ego_entry;
352         ego_entry = ego_entry->next)
353     {
354       if (0 != strcasecmp (name, ego_entry->identifier))
355         continue;
356       return ego_entry;
357     }
358   }
359   return NULL;
360 }
361
362
363 /**
364  * Callback for GET Request with subsystem
365  *
366  * @param cls the RequestHandle
367  * @param ego the Ego found
368  * @param ctx the context
369  * @param name the id of the ego
370  */
371 static void
372 ego_get_for_subsystem (void *cls,
373                        struct GNUNET_IDENTITY_Ego *ego,
374                        void **ctx,
375                        const char *name)
376 {
377   struct RequestHandle *handle = cls;
378   struct MHD_Response *resp;
379   struct GNUNET_CRYPTO_EcdsaPublicKey public_key;
380   json_t *json_root;
381   char *result_str;
382   char *public_key_string;
383
384   if(NULL == ego)
385   {
386     handle->response_code = MHD_HTTP_NOT_FOUND;
387     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
388     GNUNET_SCHEDULER_add_now (&do_error, handle);
389     return;
390   }
391
392   GNUNET_IDENTITY_ego_get_public_key(ego,&public_key);
393   public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string(&public_key);
394
395   // create json with subsystem identity
396   json_root = json_object ();
397   json_object_set_new (json_root,
398                        GNUNET_REST_IDENTITY_PARAM_PUBKEY,
399                        json_string(public_key_string));
400   json_object_set_new (json_root,
401                        GNUNET_REST_IDENTITY_PARAM_NAME,
402                        json_string(name));
403
404   result_str = json_dumps (json_root, 0);
405   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
406   resp = GNUNET_REST_create_response (result_str);
407
408   json_decref (json_root);
409   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
410   GNUNET_free(result_str);
411   GNUNET_free(public_key_string);
412   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
413 }
414
415 /**
416  * Handle identity GET request for subsystem
417  *
418  * @param con_handle the connection handle
419  * @param url the url
420  * @param cls the RequestHandle
421  */
422 void
423 ego_get_subsystem (struct GNUNET_REST_RequestHandle *con_handle,
424                    const char* url,
425                    void *cls)
426 {
427   struct RequestHandle *handle = cls;
428   char *subsystem;
429
430   if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url))
431   {
432     handle->emsg = GNUNET_strdup("Missing subsystem name");
433     GNUNET_SCHEDULER_add_now (&do_error, handle);
434     return;
435   }
436   subsystem = &handle->url[strlen (
437       GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) + 1];
438   //requested default identity of subsystem
439   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsystem);
440
441   handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
442                                     subsystem,
443                                     &ego_get_for_subsystem,
444                                     handle);
445
446   if (NULL == handle->op)
447   {
448     handle->response_code = MHD_HTTP_NOT_FOUND;
449     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
450     GNUNET_SCHEDULER_add_now (&do_error, handle);
451     return;
452   }
453 }
454
455
456 /**
457  * Handle identity GET request - responds with all identities
458  *
459  * @param con_handle the connection handle
460  * @param url the url
461  * @param cls the RequestHandle
462  */
463 void
464 ego_get_all (struct GNUNET_REST_RequestHandle *con_handle,
465              const char* url,
466              void *cls)
467 {
468   struct RequestHandle *handle = cls;
469   struct EgoEntry *ego_entry;
470   struct MHD_Response *resp;
471   json_t *json_root;
472   json_t *json_ego;
473   char *result_str;
474
475   json_root = json_array ();
476   //Return ego/egos
477   for (ego_entry = handle->ego_head;
478   NULL != ego_entry; ego_entry = ego_entry->next)
479   {
480     json_ego = json_object ();
481     json_object_set_new (json_ego,
482                          GNUNET_REST_IDENTITY_PARAM_PUBKEY,
483                          json_string (ego_entry->keystring));
484     json_object_set_new (json_ego,
485                          GNUNET_REST_IDENTITY_PARAM_NAME,
486                          json_string (ego_entry->identifier));
487     json_array_append (json_root, json_ego);
488     json_decref (json_ego);
489   }
490
491   if ((size_t) 0 == json_array_size (json_root))
492   {
493     json_decref (json_root);
494     handle->response_code = MHD_HTTP_NOT_FOUND;
495     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
496     GNUNET_SCHEDULER_add_now (&do_error, handle);
497     return;
498   }
499
500   result_str = json_dumps (json_root, 0);
501   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
502   resp = GNUNET_REST_create_response (result_str);
503
504   json_decref (json_root);
505   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
506   GNUNET_free(result_str);
507   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
508 }
509
510
511 /**
512  * Responds with the ego_entry identity
513  *
514  * @param handle the struct RequestHandle
515  * @param ego_entry the struct EgoEntry for the response
516  */
517 void
518 ego_get_response (struct RequestHandle *handle, struct EgoEntry *ego_entry)
519 {
520   struct MHD_Response *resp;
521   json_t *json_ego;
522   char *result_str;
523
524   json_ego = json_object ();
525   json_object_set_new (json_ego,
526                        GNUNET_REST_IDENTITY_PARAM_PUBKEY,
527                        json_string (ego_entry->keystring));
528   json_object_set_new (json_ego,
529                        GNUNET_REST_IDENTITY_PARAM_NAME,
530                        json_string (ego_entry->identifier));
531
532   result_str = json_dumps (json_ego, 0);
533   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
534   resp = GNUNET_REST_create_response (result_str);
535   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
536
537   json_decref (json_ego);
538   GNUNET_free(result_str);
539   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
540 }
541
542
543 /**
544  * Handle identity GET request with a public key
545  *
546  * @param con_handle the connection handle
547  * @param url the url
548  * @param cls the RequestHandle
549  */
550 void
551 ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
552                 const char* url,
553                 void *cls)
554 {
555   struct RequestHandle *handle = cls;
556   struct EgoEntry *ego_entry;
557   char *keystring;
558
559   keystring = NULL;
560
561   if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
562   {
563     handle->response_code = MHD_HTTP_NOT_FOUND;
564     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY);
565     GNUNET_SCHEDULER_add_now (&do_error, handle);
566     return;
567   }
568   keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1];
569   ego_entry = get_egoentry(handle, keystring, NULL);
570
571   if (NULL == ego_entry)
572   {
573     handle->response_code = MHD_HTTP_NOT_FOUND;
574     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
575     GNUNET_SCHEDULER_add_now (&do_error, handle);
576     return;
577   }
578
579   ego_get_response(handle, ego_entry);
580 }
581
582 /**
583  * Handle identity GET request with a name
584  *
585  * @param con_handle the connection handle
586  * @param url the url
587  * @param cls the RequestHandle
588  */
589 void
590 ego_get_name (struct GNUNET_REST_RequestHandle *con_handle,
591               const char* url,
592               void *cls)
593 {
594   struct RequestHandle *handle = cls;
595   struct EgoEntry *ego_entry;
596   char *egoname;
597
598   egoname = NULL;
599
600   if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
601   {
602     handle->response_code = MHD_HTTP_NOT_FOUND;
603     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME);
604     GNUNET_SCHEDULER_add_now (&do_error, handle);
605     return;
606   }
607   egoname = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1];
608   ego_entry = get_egoentry(handle, NULL, egoname);
609
610   if (NULL == ego_entry)
611   {
612     handle->response_code = MHD_HTTP_NOT_FOUND;
613     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
614     GNUNET_SCHEDULER_add_now (&do_error, handle);
615     return;
616   }
617
618   ego_get_response(handle, ego_entry);
619 }
620
621
622 /**
623  * Processing finished
624  *
625  * @param cls request handle
626  * @param emsg error message
627  */
628 static void
629 do_finished (void *cls, const char *emsg)
630 {
631   struct RequestHandle *handle = cls;
632   struct MHD_Response *resp;
633
634   handle->op = NULL;
635   if (NULL != emsg)
636   {
637     handle->emsg = GNUNET_strdup(emsg);
638     GNUNET_SCHEDULER_add_now (&do_error, handle);
639     return;
640   }
641   if (0 == handle->response_code)
642   {
643     handle->response_code = MHD_HTTP_NO_CONTENT;
644   }
645   resp = GNUNET_REST_create_response (NULL);
646   handle->proc (handle->proc_cls, resp, handle->response_code);
647   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
648 }
649
650
651 /**
652  * Processing edit ego with EgoEntry ego_entry
653  *
654  * @param handle the struct RequestHandle
655  * @param ego_entry the struct EgoEntry we want to edit
656  */
657 void
658 ego_edit (struct RequestHandle *handle, struct EgoEntry *ego_entry)
659 {
660   struct EgoEntry *ego_entry_tmp;
661   struct MHD_Response *resp;
662   json_t *data_js;
663   json_error_t err;
664   char *newname;
665   char term_data[handle->data_size + 1];
666   int json_state;
667
668   //if no data
669   if (0 >= handle->data_size)
670   {
671     handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
672     GNUNET_SCHEDULER_add_now (&do_error, handle);
673     return;
674   }
675   //if not json
676   term_data[handle->data_size] = '\0';
677   GNUNET_memcpy(term_data, handle->data, handle->data_size);
678   data_js = json_loads (term_data,JSON_DECODE_ANY,&err);
679
680   if (NULL == data_js)
681   {
682     handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
683     GNUNET_SCHEDULER_add_now (&do_error, handle);
684     return;
685   }
686
687   newname = NULL;
688   //NEW NAME
689   json_state = 0;
690   json_state = json_unpack(data_js,
691                            "{s:s!}",
692                            GNUNET_REST_IDENTITY_PARAM_NEWNAME,
693                            &newname);
694   //Change name with pubkey or name identifier
695   if (0 != json_state)
696   {
697
698     handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
699     GNUNET_SCHEDULER_add_now (&do_error, handle);
700     json_decref (data_js);
701     return;
702   }
703
704   if (NULL == newname)
705   {
706     handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
707     GNUNET_SCHEDULER_add_now (&do_error, handle);
708     json_decref (data_js);
709     return;
710   }
711
712   if (0 >= strlen (newname))
713   {
714     handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
715     GNUNET_SCHEDULER_add_now (&do_error, handle);
716     json_decref (data_js);
717     return;
718   }
719
720   ego_entry_tmp = get_egoentry (handle, NULL, newname);
721   if (NULL != ego_entry_tmp)
722   {
723     //Ego with same name not allowed (even if its the ego we change)
724     resp = GNUNET_REST_create_response (NULL);
725     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
726     GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
727     json_decref (data_js);
728     return;
729   }
730   handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
731                                        ego_entry->identifier,
732                                        newname,
733                                        &do_finished,
734                                        handle);
735   if (NULL == handle->op)
736   {
737     handle->emsg = GNUNET_strdup("Rename failed");
738     GNUNET_SCHEDULER_add_now (&do_error, handle);
739     json_decref (data_js);
740     return;
741   }
742   json_decref (data_js);
743   return;
744
745 }
746
747
748 /**
749  * Handle identity PUT request with public key
750  *
751  * @param con_handle the connection handle
752  * @param url the url
753  * @param cls the RequestHandle
754  */
755 void
756 ego_edit_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
757                  const char* url,
758                  void *cls)
759 {
760   struct RequestHandle *handle = cls;
761   struct EgoEntry *ego_entry;
762   char *keystring;
763
764   keystring = NULL;
765
766   if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
767   {
768     handle->response_code = MHD_HTTP_NOT_FOUND;
769     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY);
770     GNUNET_SCHEDULER_add_now (&do_error, handle);
771     return;
772   }
773   keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1];
774   ego_entry = get_egoentry(handle, keystring, NULL);
775
776   if (NULL == ego_entry)
777   {
778     handle->response_code = MHD_HTTP_NOT_FOUND;
779     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
780     GNUNET_SCHEDULER_add_now (&do_error, handle);
781     return;
782   }
783
784   ego_edit(handle,ego_entry);
785 }
786
787 /**
788  * Handle identity PUT request with name
789  *
790  * @param con_handle the connection handle
791  * @param url the url
792  * @param cls the RequestHandle
793  */
794 void
795 ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle,
796                const char* url,
797                void *cls)
798 {
799   struct RequestHandle *handle = cls;
800   struct EgoEntry *ego_entry;
801   char *name;
802
803   name = NULL;
804
805   if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
806   {
807     handle->response_code = MHD_HTTP_NOT_FOUND;
808     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME);
809     GNUNET_SCHEDULER_add_now (&do_error, handle);
810     return;
811   }
812   name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1];
813   ego_entry = get_egoentry(handle, NULL, name);
814
815   if (NULL == ego_entry)
816   {
817     handle->response_code = MHD_HTTP_NOT_FOUND;
818     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
819     GNUNET_SCHEDULER_add_now (&do_error, handle);
820     return;
821   }
822
823   ego_edit(handle,ego_entry);
824 }
825
826 /**
827  * Handle identity subsystem PUT request with name
828  *
829  * @param con_handle the connection handle
830  * @param url the url
831  * @param cls the RequestHandle
832  */
833 void
834 ego_edit_subsystem (struct GNUNET_REST_RequestHandle *con_handle,
835                     const char* url,
836                     void *cls)
837 {
838   struct RequestHandle *handle = cls;
839   struct EgoEntry *ego_entry;
840   json_t *data_js;
841   json_error_t err;
842   char *newsubsys;
843   char *name;
844   char term_data[handle->data_size + 1];
845   int json_state;
846
847   name = NULL;
848
849   if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url))
850   {
851     handle->response_code = MHD_HTTP_NOT_FOUND;
852     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME);
853     GNUNET_SCHEDULER_add_now (&do_error, handle);
854     return;
855   }
856   name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM)+1];
857   ego_entry = get_egoentry(handle, NULL, name);
858
859   if (NULL == ego_entry)
860   {
861     handle->response_code = MHD_HTTP_NOT_FOUND;
862     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
863     GNUNET_SCHEDULER_add_now (&do_error, handle);
864     return;
865   }
866
867   //if no data
868   if (0 >= handle->data_size)
869   {
870     handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
871     GNUNET_SCHEDULER_add_now (&do_error, handle);
872     return;
873   }
874   //if not json
875   term_data[handle->data_size] = '\0';
876   GNUNET_memcpy(term_data, handle->data, handle->data_size);
877   data_js = json_loads (term_data,JSON_DECODE_ANY,&err);
878
879   if (NULL == data_js)
880   {
881     handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
882     GNUNET_SCHEDULER_add_now (&do_error, handle);
883     return;
884   }
885
886   newsubsys = NULL;
887   //SUBSYSTEM
888   json_state = 0;
889   json_state = json_unpack(data_js,
890                            "{s:s!}",
891                            GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM,
892                            &newsubsys);
893   //Change subsystem with pubkey or name identifier
894   if (0 != json_state)
895   {
896     handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
897     GNUNET_SCHEDULER_add_now (&do_error, handle);
898     json_decref (data_js);
899     return;
900   }
901
902   if (NULL == newsubsys)
903   {
904     handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
905     GNUNET_SCHEDULER_add_now (&do_error, handle);
906     json_decref (data_js);
907     return;
908   }
909
910   if (0 >= strlen (newsubsys))
911   {
912     handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
913     GNUNET_SCHEDULER_add_now (&do_error, handle);
914     json_decref (data_js);
915     return;
916   }
917
918   handle->response_code = MHD_HTTP_NO_CONTENT;
919   handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
920                                     newsubsys,
921                                     ego_entry->ego,
922                                     &do_finished,
923                                     handle);
924   if (NULL == handle->op)
925   {
926     handle->emsg = GNUNET_strdup("Setting subsystem failed");
927     GNUNET_SCHEDULER_add_now (&do_error, handle);
928     return;
929   }
930   json_decref (data_js);
931   return;
932
933 }
934
935 /**
936  * Handle identity POST request
937  *
938  * @param con_handle the connection handle
939  * @param url the url
940  * @param cls the RequestHandle
941  */
942 void
943 ego_create (struct GNUNET_REST_RequestHandle *con_handle,
944             const char* url,
945             void *cls)
946 {
947   struct RequestHandle *handle = cls;
948   struct EgoEntry *ego_entry;
949   struct MHD_Response *resp;
950   json_t *data_js;
951   json_error_t err;
952   char* egoname;
953   int json_unpack_state;
954   char term_data[handle->data_size + 1];
955
956   if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
957   {
958     GNUNET_SCHEDULER_add_now (&do_error, handle);
959     return;
960   }
961
962   if (0 >= handle->data_size)
963   {
964     handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
965     GNUNET_SCHEDULER_add_now (&do_error, handle);
966     return;
967   }
968   term_data[handle->data_size] = '\0';
969   GNUNET_memcpy(term_data, handle->data, handle->data_size);
970   data_js = json_loads (term_data,
971                         JSON_DECODE_ANY,
972                         &err);
973   if (NULL == data_js)
974   {
975     handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
976     GNUNET_SCHEDULER_add_now (&do_error, handle);
977     json_decref (data_js);
978     return;
979   }
980   json_unpack_state = 0;
981   json_unpack_state = json_unpack(data_js,
982                                   "{s:s!}",
983                                   GNUNET_REST_IDENTITY_PARAM_NAME,
984                                   &egoname);
985   if (0 != json_unpack_state)
986   {
987     handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
988     GNUNET_SCHEDULER_add_now (&do_error, handle);
989     json_decref (data_js);
990     return;
991   }
992
993   if (NULL == egoname)
994   {
995     handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
996     GNUNET_SCHEDULER_add_now (&do_error, handle);
997     json_decref (data_js);
998     return;
999   }
1000   if (0 >= strlen (egoname))
1001   {
1002     json_decref (data_js);
1003     handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
1004     GNUNET_SCHEDULER_add_now (&do_error, handle);
1005     return;
1006   }
1007   GNUNET_STRINGS_utf8_tolower(egoname, egoname);
1008   for (ego_entry = handle->ego_head;
1009   NULL != ego_entry; ego_entry = ego_entry->next)
1010   {
1011     if (0 == strcasecmp (egoname, ego_entry->identifier))
1012     {
1013       resp = GNUNET_REST_create_response (NULL);
1014       handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
1015       GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
1016       json_decref (data_js);
1017       return;
1018     }
1019   }
1020   handle->name = GNUNET_strdup(egoname);
1021   json_decref (data_js);
1022   handle->response_code = MHD_HTTP_CREATED;
1023   handle->op = GNUNET_IDENTITY_create (handle->identity_handle, handle->name,
1024                                        &do_finished, handle);
1025 }
1026
1027 /**
1028  * Handle identity DELETE request with public key
1029  *
1030  * @param con_handle the connection handle
1031  * @param url the url
1032  * @param cls the RequestHandle
1033  */
1034 void
1035 ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
1036                    const char* url,
1037                    void *cls)
1038 {
1039   struct RequestHandle *handle = cls;
1040   struct EgoEntry *ego_entry;
1041   char *keystring;
1042
1043   keystring = NULL;
1044
1045   if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
1046   {
1047     handle->response_code = MHD_HTTP_NOT_FOUND;
1048     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY);
1049     GNUNET_SCHEDULER_add_now (&do_error, handle);
1050     return;
1051   }
1052   keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1];
1053   ego_entry = get_egoentry(handle, keystring, NULL);
1054
1055   if (NULL == ego_entry)
1056   {
1057     handle->response_code = MHD_HTTP_NOT_FOUND;
1058     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
1059     GNUNET_SCHEDULER_add_now (&do_error, handle);
1060     return;
1061   }
1062
1063   handle->response_code = MHD_HTTP_NO_CONTENT;
1064   handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
1065                                        ego_entry->identifier,
1066                                        &do_finished,
1067                                        handle);
1068 }
1069
1070
1071 /**
1072  * Handle identity DELETE request with name
1073  *
1074  * @param con_handle the connection handle
1075  * @param url the url
1076  * @param cls the RequestHandle
1077  */
1078 void
1079 ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle,
1080                    const char* url,
1081                    void *cls)
1082 {
1083   struct RequestHandle *handle = cls;
1084   struct EgoEntry *ego_entry;
1085   char *name;
1086
1087   name = NULL;
1088
1089   if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
1090   {
1091     handle->response_code = MHD_HTTP_NOT_FOUND;
1092     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME);
1093     GNUNET_SCHEDULER_add_now (&do_error, handle);
1094     return;
1095   }
1096   name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1];
1097   ego_entry = get_egoentry(handle, NULL, name);
1098
1099   if (NULL == ego_entry)
1100   {
1101     handle->response_code = MHD_HTTP_NOT_FOUND;
1102     handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
1103     GNUNET_SCHEDULER_add_now (&do_error, handle);
1104     return;
1105   }
1106
1107   handle->response_code = MHD_HTTP_NO_CONTENT;
1108   handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
1109                                        ego_entry->identifier,
1110                                        &do_finished,
1111                                        handle);
1112 }
1113
1114
1115 /**
1116  * Respond to OPTIONS request
1117  *
1118  * @param con_handle the connection handle
1119  * @param url the url
1120  * @param cls the RequestHandle
1121  */
1122 static void
1123 options_cont (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
1124               void *cls)
1125 {
1126   struct MHD_Response *resp;
1127   struct RequestHandle *handle = cls;
1128
1129   //For now, independent of path return all options
1130   resp = GNUNET_REST_create_response (NULL);
1131   MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
1132   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1133   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
1134   return;
1135 }
1136
1137 /**
1138  * Handle rest request
1139  *
1140  * @param handle the request handle
1141  */
1142 static void
1143 init_cont (struct RequestHandle *handle)
1144 {
1145   struct GNUNET_REST_RequestHandlerError err;
1146   static const struct GNUNET_REST_RequestHandler handlers[] = {
1147       { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ALL, &ego_get_all },
1148       { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_get_pubkey },
1149       { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_get_name },
1150       { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_get_subsystem },
1151       { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_edit_pubkey },
1152       { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_edit_name },
1153       { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_edit_subsystem },
1154       { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create },
1155       { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_delete_pubkey },
1156       { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_delete_name },
1157       { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont },
1158       GNUNET_REST_HANDLER_END
1159   };
1160
1161   if (GNUNET_NO
1162       == GNUNET_REST_handle_request (handle->rest_handle, handlers, &err,
1163                                      handle))
1164   {
1165     handle->response_code = err.error_code;
1166     GNUNET_SCHEDULER_add_now (&do_error, handle);
1167   }
1168 }
1169
1170 /**
1171  * If listing is enabled, prints information about the egos.
1172  *
1173  * This function is initially called for all egos and then again
1174  * whenever a ego's identifier changes or if it is deleted.  At the
1175  * end of the initial pass over all egos, the function is once called
1176  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1177  * be invoked in the future or that there was an error.
1178  *
1179  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1180  * this function is only called ONCE, and 'NULL' being passed in
1181  * 'ego' does indicate an error (i.e. name is taken or no default
1182  * value is known).  If 'ego' is non-NULL and if '*ctx'
1183  * is set in those callbacks, the value WILL be passed to a subsequent
1184  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1185  * that one was not NULL).
1186  *
1187  * When an identity is renamed, this function is called with the
1188  * (known) ego but the NEW identifier.
1189  *
1190  * When an identity is deleted, this function is called with the
1191  * (known) ego and "NULL" for the 'identifier'.  In this case,
1192  * the 'ego' is henceforth invalid (and the 'ctx' should also be
1193  * cleaned up).
1194  *
1195  * @param cls closure
1196  * @param ego ego handle
1197  * @param ctx context for application to store data for this ego
1198  *                 (during the lifetime of this process, initially NULL)
1199  * @param identifier identifier assigned by the user for this ego,
1200  *                   NULL if the user just deleted the ego and it
1201  *                   must thus no longer be used
1202  */
1203 static void
1204 init_egos (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx,
1205            const char *identifier)
1206 {
1207   struct RequestHandle *handle = cls;
1208   struct EgoEntry *ego_entry;
1209   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1210
1211   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1212   {
1213     handle->state = ID_REST_STATE_POST_INIT;
1214     init_cont (handle);
1215     return;
1216   }
1217   if (ID_REST_STATE_INIT == handle->state)
1218   {
1219     ego_entry = GNUNET_new(struct EgoEntry);
1220     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1221     ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1222     ego_entry->ego = ego;
1223     GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
1224     GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail,
1225                                      ego_entry);
1226   }
1227 }
1228
1229 /**
1230  * Function processing the REST call
1231  *
1232  * @param method HTTP method
1233  * @param url URL of the HTTP request
1234  * @param data body of the HTTP request (optional)
1235  * @param data_size length of the body
1236  * @param proc callback function for the result
1237  * @param proc_cls closure for callback function
1238  * @return GNUNET_OK if request accepted
1239  */
1240 static void
1241 rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1242                       GNUNET_REST_ResultProcessor proc, void *proc_cls)
1243 {
1244   struct RequestHandle *handle = GNUNET_new(struct RequestHandle);
1245
1246   handle->response_code = 0;
1247   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1248   handle->proc_cls = proc_cls;
1249   handle->proc = proc;
1250   handle->rest_handle = rest_handle;
1251   handle->data = rest_handle->data;
1252   handle->data_size = rest_handle->data_size;
1253
1254   handle->url = GNUNET_strdup(rest_handle->url);
1255   if (handle->url[strlen (handle->url) - 1] == '/')
1256     handle->url[strlen (handle->url) - 1] = '\0';
1257   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1258
1259   handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &init_egos, handle);
1260
1261   handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1262                                                        &do_error, handle);
1263
1264   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1265 }
1266
1267 /**
1268  * Entry point for the plugin.
1269  *
1270  * @param cls Config info
1271  * @return NULL on error, otherwise the plugin context
1272  */
1273 void *
1274 libgnunet_plugin_rest_identity_init (void *cls)
1275 {
1276   static struct Plugin plugin;
1277   struct GNUNET_REST_Plugin *api;
1278
1279   cfg = cls;
1280   if (NULL != plugin.cfg)
1281     return NULL; /* can only initialize once! */
1282   memset (&plugin, 0, sizeof(struct Plugin));
1283   plugin.cfg = cfg;
1284   api = GNUNET_new(struct GNUNET_REST_Plugin);
1285   api->cls = &plugin;
1286   api->name = GNUNET_REST_API_NS_IDENTITY;
1287   api->process_request = &rest_process_request;
1288   GNUNET_asprintf (&allow_methods, "%s, %s, %s, %s, %s",
1289                    MHD_HTTP_METHOD_GET,
1290                    MHD_HTTP_METHOD_POST,
1291                    MHD_HTTP_METHOD_PUT,
1292                    MHD_HTTP_METHOD_DELETE,
1293                    MHD_HTTP_METHOD_OPTIONS);
1294
1295   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Identity REST API initialized\n"));
1296   return api;
1297 }
1298
1299 /**
1300  * Exit point from the plugin.
1301  *
1302  * @param cls the plugin context (as returned by "init")
1303  * @return always NULL
1304  */
1305 void *
1306 libgnunet_plugin_rest_identity_done (void *cls)
1307 {
1308   struct GNUNET_REST_Plugin *api = cls;
1309   struct Plugin *plugin = api->cls;
1310   plugin->cfg = NULL;
1311
1312   GNUNET_free_non_null(allow_methods);
1313   GNUNET_free(api);
1314   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n");
1315   return NULL;
1316 }
1317
1318 /* end of plugin_rest_identity.c */
1319