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