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