2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @author Martin Schanzenbach
22 * @author Philippe Buschmann
23 * @file identity/plugin_rest_identity.c
24 * @brief GNUnet Identity REST plugin
28 #include "gnunet_rest_plugin.h"
29 #include "gnunet_identity_service.h"
30 #include "gnunet_rest_lib.h"
31 #include "microhttpd.h"
37 #define GNUNET_REST_API_NS_IDENTITY "/identity"
40 * Identity Namespace with public key specifier
42 #define GNUNET_REST_API_NS_IDENTITY_PUBKEY "/identity/pubkey"
45 * Identity Namespace with public key specifier
47 #define GNUNET_REST_API_NS_IDENTITY_NAME "/identity/name"
50 * Identity Subsystem Namespace
52 #define GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM "/identity/subsystem"
55 * Parameter public key
57 #define GNUNET_REST_IDENTITY_PARAM_PUBKEY "pubkey"
62 #define GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM "subsystem"
67 #define GNUNET_REST_IDENTITY_PARAM_NAME "name"
72 #define GNUNET_REST_IDENTITY_PARAM_NEWNAME "newname"
75 * Error message Unknown Error
77 #define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error"
80 * Error message No identity found
82 #define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found"
85 * Error message Missing identity name
87 #define GNUNET_REST_IDENTITY_MISSING_NAME "Missing identity name"
90 * Error message Missing identity name
92 #define GNUNET_REST_IDENTITY_MISSING_PUBKEY "Missing identity public key"
95 * Error message No data
97 #define GNUNET_REST_ERROR_NO_DATA "No data"
100 * Error message Data invalid
102 #define GNUNET_REST_ERROR_DATA_INVALID "Data invalid"
105 * State while collecting all egos
107 #define ID_REST_STATE_INIT 0
110 * Done collecting egos
112 #define ID_REST_STATE_POST_INIT 1
115 * The configuration handle
117 const struct GNUNET_CONFIGURATION_Handle *cfg;
120 * HTTP methods allows for this plugin
122 static char *allow_methods;
125 * @brief struct returned by the initialization function of the plugin
129 const struct GNUNET_CONFIGURATION_Handle *cfg;
140 struct EgoEntry *next;
145 struct EgoEntry *prev;
160 struct GNUNET_IDENTITY_Ego *ego;
169 * The data from the REST request
174 * The name to look up
179 * the length of the REST data
187 struct EgoEntry *ego_head;
192 struct EgoEntry *ego_tail;
195 * The processing state
200 * Handle to Identity service.
202 struct GNUNET_IDENTITY_Handle *identity_handle;
207 struct GNUNET_IDENTITY_Operation *op;
212 struct GNUNET_REST_RequestHandle *rest_handle;
215 * Desired timeout for the lookup (default is no timeout).
217 struct GNUNET_TIME_Relative timeout;
220 * ID of a task associated with the resolution process.
222 struct GNUNET_SCHEDULER_Task *timeout_task;
225 * The plugin result processor
227 GNUNET_REST_ResultProcessor proc;
230 * The closure of the result processor
240 * Error response message
251 * Cleanup lookup handle
252 * @param handle Handle to clean up
255 cleanup_handle (void *cls)
257 struct RequestHandle *handle = cls;
258 struct EgoEntry *ego_entry;
259 struct EgoEntry *ego_tmp;
261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
262 if (NULL != handle->timeout_task)
264 GNUNET_SCHEDULER_cancel (handle->timeout_task);
265 handle->timeout_task = NULL;
268 if (NULL != handle->url)
269 GNUNET_free (handle->url);
270 if (NULL != handle->emsg)
271 GNUNET_free (handle->emsg);
272 if (NULL != handle->name)
273 GNUNET_free (handle->name);
274 if (NULL != handle->identity_handle)
275 GNUNET_IDENTITY_disconnect (handle->identity_handle);
277 for (ego_entry = handle->ego_head; NULL != ego_entry;)
280 ego_entry = ego_entry->next;
281 GNUNET_free (ego_tmp->identifier);
282 GNUNET_free (ego_tmp->keystring);
283 GNUNET_free (ego_tmp);
286 GNUNET_free (handle);
291 * Task run on errors. Reports an error and cleans up everything.
293 * @param cls the `struct RequestHandle`
298 struct RequestHandle *handle = cls;
299 struct MHD_Response *resp;
300 json_t *json_error = json_object ();
303 if (NULL == handle->emsg)
304 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_ERROR_UNKNOWN);
306 json_object_set_new (json_error, "error", json_string (handle->emsg));
308 if (0 == handle->response_code)
309 handle->response_code = MHD_HTTP_OK;
310 response = json_dumps (json_error, 0);
311 resp = GNUNET_REST_create_response (response);
312 handle->proc (handle->proc_cls, resp, handle->response_code);
313 json_decref (json_error);
314 GNUNET_free (response);
315 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
320 * Get EgoEntry from list with either a public key or a name
321 * If public key and name are not NULL, it returns the public key result first
323 * @param handle the RequestHandle
324 * @param pubkey the public key of an identity (only one can be NULL)
325 * @param name the name of an identity (only one can be NULL)
326 * @return EgoEntry or NULL if not found
329 get_egoentry (struct RequestHandle *handle, char *pubkey, char *name)
331 struct EgoEntry *ego_entry;
335 for (ego_entry = handle->ego_head; NULL != ego_entry;
336 ego_entry = ego_entry->next)
338 if (0 != strcasecmp (pubkey, ego_entry->keystring))
345 for (ego_entry = handle->ego_head; NULL != ego_entry;
346 ego_entry = ego_entry->next)
348 if (0 != strcasecmp (name, ego_entry->identifier))
358 * Callback for GET Request with subsystem
360 * @param cls the RequestHandle
361 * @param ego the Ego found
362 * @param ctx the context
363 * @param name the id of the ego
366 ego_get_for_subsystem (void *cls,
367 struct GNUNET_IDENTITY_Ego *ego,
371 struct RequestHandle *handle = cls;
372 struct MHD_Response *resp;
373 struct GNUNET_CRYPTO_EcdsaPublicKey public_key;
376 char *public_key_string;
380 handle->response_code = MHD_HTTP_NOT_FOUND;
381 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
382 GNUNET_SCHEDULER_add_now (&do_error, handle);
386 GNUNET_IDENTITY_ego_get_public_key (ego, &public_key);
387 public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string (&public_key);
389 // create json with subsystem identity
390 json_root = json_object ();
391 json_object_set_new (json_root,
392 GNUNET_REST_IDENTITY_PARAM_PUBKEY,
393 json_string (public_key_string));
394 json_object_set_new (json_root,
395 GNUNET_REST_IDENTITY_PARAM_NAME,
398 result_str = json_dumps (json_root, 0);
399 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
400 resp = GNUNET_REST_create_response (result_str);
402 json_decref (json_root);
403 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
404 GNUNET_free (result_str);
405 GNUNET_free (public_key_string);
406 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
411 * Handle identity GET request for subsystem
413 * @param con_handle the connection handle
415 * @param cls the RequestHandle
418 ego_get_subsystem (struct GNUNET_REST_RequestHandle *con_handle,
422 struct RequestHandle *handle = cls;
425 if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url))
427 handle->emsg = GNUNET_strdup ("Missing subsystem name");
428 GNUNET_SCHEDULER_add_now (&do_error, handle);
431 subsystem = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) + 1];
432 // requested default identity of subsystem
433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsystem);
435 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
437 &ego_get_for_subsystem,
440 if (NULL == handle->op)
442 handle->response_code = MHD_HTTP_NOT_FOUND;
443 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
444 GNUNET_SCHEDULER_add_now (&do_error, handle);
451 * Handle identity GET request - responds with all identities
453 * @param con_handle the connection handle
455 * @param cls the RequestHandle
458 ego_get_all (struct GNUNET_REST_RequestHandle *con_handle,
462 struct RequestHandle *handle = cls;
463 struct EgoEntry *ego_entry;
464 struct MHD_Response *resp;
469 json_root = json_array ();
471 for (ego_entry = handle->ego_head; NULL != ego_entry;
472 ego_entry = ego_entry->next)
474 json_ego = json_object ();
475 json_object_set_new (json_ego,
476 GNUNET_REST_IDENTITY_PARAM_PUBKEY,
477 json_string (ego_entry->keystring));
478 json_object_set_new (json_ego,
479 GNUNET_REST_IDENTITY_PARAM_NAME,
480 json_string (ego_entry->identifier));
481 json_array_append (json_root, json_ego);
482 json_decref (json_ego);
485 result_str = json_dumps (json_root, 0);
486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
487 resp = GNUNET_REST_create_response (result_str);
489 json_decref (json_root);
490 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
491 GNUNET_free (result_str);
492 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
497 * Responds with the ego_entry identity
499 * @param handle the struct RequestHandle
500 * @param ego_entry the struct EgoEntry for the response
503 ego_get_response (struct RequestHandle *handle, struct EgoEntry *ego_entry)
505 struct MHD_Response *resp;
509 json_ego = json_object ();
510 json_object_set_new (json_ego,
511 GNUNET_REST_IDENTITY_PARAM_PUBKEY,
512 json_string (ego_entry->keystring));
513 json_object_set_new (json_ego,
514 GNUNET_REST_IDENTITY_PARAM_NAME,
515 json_string (ego_entry->identifier));
517 result_str = json_dumps (json_ego, 0);
518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
519 resp = GNUNET_REST_create_response (result_str);
520 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
522 json_decref (json_ego);
523 GNUNET_free (result_str);
524 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
529 * Handle identity GET request with a public key
531 * @param con_handle the connection handle
533 * @param cls the RequestHandle
536 ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
540 struct RequestHandle *handle = cls;
541 struct EgoEntry *ego_entry;
546 if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
548 handle->response_code = MHD_HTTP_NOT_FOUND;
549 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_MISSING_PUBKEY);
550 GNUNET_SCHEDULER_add_now (&do_error, handle);
553 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) + 1];
554 ego_entry = get_egoentry (handle, keystring, NULL);
556 if (NULL == ego_entry)
558 handle->response_code = MHD_HTTP_NOT_FOUND;
559 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
560 GNUNET_SCHEDULER_add_now (&do_error, handle);
564 ego_get_response (handle, ego_entry);
569 * Handle identity GET request with a name
571 * @param con_handle the connection handle
573 * @param cls the RequestHandle
576 ego_get_name (struct GNUNET_REST_RequestHandle *con_handle,
580 struct RequestHandle *handle = cls;
581 struct EgoEntry *ego_entry;
586 if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
588 handle->response_code = MHD_HTTP_NOT_FOUND;
589 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_MISSING_NAME);
590 GNUNET_SCHEDULER_add_now (&do_error, handle);
593 egoname = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME) + 1];
594 ego_entry = get_egoentry (handle, NULL, egoname);
596 if (NULL == ego_entry)
598 handle->response_code = MHD_HTTP_NOT_FOUND;
599 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
600 GNUNET_SCHEDULER_add_now (&do_error, handle);
604 ego_get_response (handle, ego_entry);
609 * Processing finished
611 * @param cls request handle
612 * @param emsg error message
615 do_finished (void *cls, const char *emsg)
617 struct RequestHandle *handle = cls;
618 struct MHD_Response *resp;
623 handle->emsg = GNUNET_strdup (emsg);
624 GNUNET_SCHEDULER_add_now (&do_error, handle);
627 if (0 == handle->response_code)
629 handle->response_code = MHD_HTTP_NO_CONTENT;
631 resp = GNUNET_REST_create_response (NULL);
632 handle->proc (handle->proc_cls, resp, handle->response_code);
633 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
638 * Processing finished, when creating an ego.
640 * @param cls request handle
641 * @param private key of the ego, or NULL on error
642 * @param emsg error message
645 do_finished_create (void *cls,
646 const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
649 struct RequestHandle *handle = cls;
652 do_finished (handle, emsg);
657 * Processing edit ego with EgoEntry ego_entry
659 * @param handle the struct RequestHandle
660 * @param ego_entry the struct EgoEntry we want to edit
663 ego_edit (struct RequestHandle *handle, struct EgoEntry *ego_entry)
665 struct EgoEntry *ego_entry_tmp;
666 struct MHD_Response *resp;
670 char term_data[handle->data_size + 1];
674 if (0 >= handle->data_size)
676 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
677 GNUNET_SCHEDULER_add_now (&do_error, handle);
681 term_data[handle->data_size] = '\0';
682 GNUNET_memcpy (term_data, handle->data, handle->data_size);
683 data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
687 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
688 GNUNET_SCHEDULER_add_now (&do_error, handle);
695 json_state = json_unpack (data_js,
697 GNUNET_REST_IDENTITY_PARAM_NEWNAME,
699 // Change name with pubkey or name identifier
702 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
703 GNUNET_SCHEDULER_add_now (&do_error, handle);
704 json_decref (data_js);
710 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
711 GNUNET_SCHEDULER_add_now (&do_error, handle);
712 json_decref (data_js);
716 if (0 >= strlen (newname))
718 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
719 GNUNET_SCHEDULER_add_now (&do_error, handle);
720 json_decref (data_js);
724 ego_entry_tmp = get_egoentry (handle, NULL, newname);
725 if (NULL != ego_entry_tmp)
727 // Ego with same name not allowed (even if its the ego we change)
728 resp = GNUNET_REST_create_response (NULL);
729 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
730 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
731 json_decref (data_js);
734 handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
735 ego_entry->identifier,
739 if (NULL == handle->op)
741 handle->emsg = GNUNET_strdup ("Rename failed");
742 GNUNET_SCHEDULER_add_now (&do_error, handle);
743 json_decref (data_js);
746 json_decref (data_js);
752 * Handle identity PUT request with public key
754 * @param con_handle the connection handle
756 * @param cls the RequestHandle
759 ego_edit_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
763 struct RequestHandle *handle = cls;
764 struct EgoEntry *ego_entry;
769 if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
771 handle->response_code = MHD_HTTP_NOT_FOUND;
772 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_MISSING_PUBKEY);
773 GNUNET_SCHEDULER_add_now (&do_error, handle);
776 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) + 1];
777 ego_entry = get_egoentry (handle, keystring, NULL);
779 if (NULL == ego_entry)
781 handle->response_code = MHD_HTTP_NOT_FOUND;
782 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
783 GNUNET_SCHEDULER_add_now (&do_error, handle);
787 ego_edit (handle, ego_entry);
792 * Handle identity PUT request with name
794 * @param con_handle the connection handle
796 * @param cls the RequestHandle
799 ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle,
803 struct RequestHandle *handle = cls;
804 struct EgoEntry *ego_entry;
809 if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
811 handle->response_code = MHD_HTTP_NOT_FOUND;
812 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_MISSING_NAME);
813 GNUNET_SCHEDULER_add_now (&do_error, handle);
816 name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME) + 1];
817 ego_entry = get_egoentry (handle, NULL, name);
819 if (NULL == ego_entry)
821 handle->response_code = MHD_HTTP_NOT_FOUND;
822 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
823 GNUNET_SCHEDULER_add_now (&do_error, handle);
827 ego_edit (handle, ego_entry);
832 * Handle identity subsystem PUT request with name
834 * @param con_handle the connection handle
836 * @param cls the RequestHandle
839 ego_edit_subsystem (struct GNUNET_REST_RequestHandle *con_handle,
843 struct RequestHandle *handle = cls;
844 struct EgoEntry *ego_entry;
849 char term_data[handle->data_size + 1];
854 if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url))
856 handle->response_code = MHD_HTTP_NOT_FOUND;
857 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_MISSING_NAME);
858 GNUNET_SCHEDULER_add_now (&do_error, handle);
861 name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) + 1];
862 ego_entry = get_egoentry (handle, NULL, name);
864 if (NULL == ego_entry)
866 handle->response_code = MHD_HTTP_NOT_FOUND;
867 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
868 GNUNET_SCHEDULER_add_now (&do_error, handle);
873 if (0 >= handle->data_size)
875 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
876 GNUNET_SCHEDULER_add_now (&do_error, handle);
880 term_data[handle->data_size] = '\0';
881 GNUNET_memcpy (term_data, handle->data, handle->data_size);
882 data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
886 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
887 GNUNET_SCHEDULER_add_now (&do_error, handle);
894 json_state = json_unpack (data_js,
896 GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM,
898 // Change subsystem with pubkey or name identifier
901 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
902 GNUNET_SCHEDULER_add_now (&do_error, handle);
903 json_decref (data_js);
907 if (NULL == newsubsys)
909 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
910 GNUNET_SCHEDULER_add_now (&do_error, handle);
911 json_decref (data_js);
915 if (0 >= strlen (newsubsys))
917 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
918 GNUNET_SCHEDULER_add_now (&do_error, handle);
919 json_decref (data_js);
923 handle->response_code = MHD_HTTP_NO_CONTENT;
924 handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
929 if (NULL == handle->op)
931 handle->emsg = GNUNET_strdup ("Setting subsystem failed");
932 GNUNET_SCHEDULER_add_now (&do_error, handle);
935 json_decref (data_js);
941 * Handle identity POST request
943 * @param con_handle the connection handle
945 * @param cls the RequestHandle
948 ego_create (struct GNUNET_REST_RequestHandle *con_handle,
952 struct RequestHandle *handle = cls;
953 struct EgoEntry *ego_entry;
954 struct MHD_Response *resp;
958 int json_unpack_state;
959 char term_data[handle->data_size + 1];
961 if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
963 GNUNET_SCHEDULER_add_now (&do_error, handle);
967 if (0 >= handle->data_size)
969 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
970 GNUNET_SCHEDULER_add_now (&do_error, handle);
973 term_data[handle->data_size] = '\0';
974 GNUNET_memcpy (term_data, handle->data, handle->data_size);
975 data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
978 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
979 GNUNET_SCHEDULER_add_now (&do_error, handle);
980 json_decref (data_js);
983 json_unpack_state = 0;
985 json_unpack (data_js, "{s:s!}", GNUNET_REST_IDENTITY_PARAM_NAME, &egoname);
986 if (0 != json_unpack_state)
988 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
989 GNUNET_SCHEDULER_add_now (&do_error, handle);
990 json_decref (data_js);
996 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
997 GNUNET_SCHEDULER_add_now (&do_error, handle);
998 json_decref (data_js);
1001 if (0 >= strlen (egoname))
1003 json_decref (data_js);
1004 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
1005 GNUNET_SCHEDULER_add_now (&do_error, handle);
1008 GNUNET_STRINGS_utf8_tolower (egoname, egoname);
1009 for (ego_entry = handle->ego_head; NULL != ego_entry;
1010 ego_entry = ego_entry->next)
1012 if (0 == strcasecmp (egoname, ego_entry->identifier))
1014 resp = GNUNET_REST_create_response (NULL);
1015 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
1016 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
1017 json_decref (data_js);
1021 handle->name = GNUNET_strdup (egoname);
1022 json_decref (data_js);
1023 handle->response_code = MHD_HTTP_CREATED;
1024 handle->op = GNUNET_IDENTITY_create (handle->identity_handle,
1026 &do_finished_create,
1032 * Handle identity DELETE request with public key
1034 * @param con_handle the connection handle
1035 * @param url the url
1036 * @param cls the RequestHandle
1039 ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
1043 struct RequestHandle *handle = cls;
1044 struct EgoEntry *ego_entry;
1049 if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
1051 handle->response_code = MHD_HTTP_NOT_FOUND;
1052 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_MISSING_PUBKEY);
1053 GNUNET_SCHEDULER_add_now (&do_error, handle);
1056 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) + 1];
1057 ego_entry = get_egoentry (handle, keystring, NULL);
1059 if (NULL == ego_entry)
1061 handle->response_code = MHD_HTTP_NOT_FOUND;
1062 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
1063 GNUNET_SCHEDULER_add_now (&do_error, handle);
1067 handle->response_code = MHD_HTTP_NO_CONTENT;
1068 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
1069 ego_entry->identifier,
1076 * Handle identity DELETE request with name
1078 * @param con_handle the connection handle
1079 * @param url the url
1080 * @param cls the RequestHandle
1083 ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle,
1087 struct RequestHandle *handle = cls;
1088 struct EgoEntry *ego_entry;
1093 if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
1095 handle->response_code = MHD_HTTP_NOT_FOUND;
1096 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_MISSING_NAME);
1097 GNUNET_SCHEDULER_add_now (&do_error, handle);
1100 name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME) + 1];
1101 ego_entry = get_egoentry (handle, NULL, name);
1103 if (NULL == ego_entry)
1105 handle->response_code = MHD_HTTP_NOT_FOUND;
1106 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
1107 GNUNET_SCHEDULER_add_now (&do_error, handle);
1111 handle->response_code = MHD_HTTP_NO_CONTENT;
1112 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
1113 ego_entry->identifier,
1120 * Respond to OPTIONS request
1122 * @param con_handle the connection handle
1123 * @param url the url
1124 * @param cls the RequestHandle
1127 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1131 struct MHD_Response *resp;
1132 struct RequestHandle *handle = cls;
1134 // For now, independent of path return all options
1135 resp = GNUNET_REST_create_response (NULL);
1136 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
1137 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1138 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
1144 * Handle rest request
1146 * @param handle the request handle
1149 init_cont (struct RequestHandle *handle)
1151 struct GNUNET_REST_RequestHandlerError err;
1152 static const struct GNUNET_REST_RequestHandler handlers[] =
1153 { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_get_all },
1154 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PUBKEY,
1156 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_get_name },
1157 { MHD_HTTP_METHOD_GET,
1158 GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM,
1159 &ego_get_subsystem },
1160 { MHD_HTTP_METHOD_PUT,
1161 GNUNET_REST_API_NS_IDENTITY_PUBKEY,
1163 { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_edit_name },
1164 { MHD_HTTP_METHOD_PUT,
1165 GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM,
1166 &ego_edit_subsystem },
1167 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create },
1168 { MHD_HTTP_METHOD_DELETE,
1169 GNUNET_REST_API_NS_IDENTITY_PUBKEY,
1170 &ego_delete_pubkey },
1171 { MHD_HTTP_METHOD_DELETE,
1172 GNUNET_REST_API_NS_IDENTITY_NAME,
1174 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont },
1175 GNUNET_REST_HANDLER_END };
1178 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1180 handle->response_code = err.error_code;
1181 GNUNET_SCHEDULER_add_now (&do_error, handle);
1187 * If listing is enabled, prints information about the egos.
1189 * This function is initially called for all egos and then again
1190 * whenever a ego's identifier changes or if it is deleted. At the
1191 * end of the initial pass over all egos, the function is once called
1192 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1193 * be invoked in the future or that there was an error.
1195 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1196 * this function is only called ONCE, and 'NULL' being passed in
1197 * 'ego' does indicate an error (i.e. name is taken or no default
1198 * value is known). If 'ego' is non-NULL and if '*ctx'
1199 * is set in those callbacks, the value WILL be passed to a subsequent
1200 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1201 * that one was not NULL).
1203 * When an identity is renamed, this function is called with the
1204 * (known) ego but the NEW identifier.
1206 * When an identity is deleted, this function is called with the
1207 * (known) ego and "NULL" for the 'identifier'. In this case,
1208 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1211 * @param cls closure
1212 * @param ego ego handle
1213 * @param ctx context for application to store data for this ego
1214 * (during the lifetime of this process, initially NULL)
1215 * @param identifier identifier assigned by the user for this ego,
1216 * NULL if the user just deleted the ego and it
1217 * must thus no longer be used
1220 init_egos (void *cls,
1221 struct GNUNET_IDENTITY_Ego *ego,
1223 const char *identifier)
1225 struct RequestHandle *handle = cls;
1226 struct EgoEntry *ego_entry;
1227 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1229 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1231 handle->state = ID_REST_STATE_POST_INIT;
1235 if (ID_REST_STATE_INIT == handle->state)
1237 ego_entry = GNUNET_new (struct EgoEntry);
1238 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1239 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1240 ego_entry->ego = ego;
1241 ego_entry->identifier = GNUNET_strdup (identifier);
1242 GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
1247 // Check if ego exists
1248 for (ego_entry = handle->ego_head; NULL != ego_entry;)
1250 struct EgoEntry *tmp = ego_entry;
1251 ego_entry = ego_entry->next;
1252 if (ego != tmp->ego)
1255 if (NULL == identifier)
1257 GNUNET_CONTAINER_DLL_remove (handle->ego_head,
1260 GNUNET_free (tmp->keystring);
1261 GNUNET_free (tmp->identifier);
1267 GNUNET_free (tmp->identifier);
1268 tmp->identifier = GNUNET_strdup (identifier);
1273 ego_entry = GNUNET_new (struct EgoEntry);
1274 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1275 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1276 ego_entry->ego = ego;
1277 GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
1278 GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
1286 * Function processing the REST call
1288 * @param method HTTP method
1289 * @param url URL of the HTTP request
1290 * @param data body of the HTTP request (optional)
1291 * @param data_size length of the body
1292 * @param proc callback function for the result
1293 * @param proc_cls closure for callback function
1294 * @return GNUNET_OK if request accepted
1297 rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1298 GNUNET_REST_ResultProcessor proc,
1301 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1303 handle->response_code = 0;
1304 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1305 handle->proc_cls = proc_cls;
1306 handle->proc = proc;
1307 handle->rest_handle = rest_handle;
1308 handle->data = rest_handle->data;
1309 handle->data_size = rest_handle->data_size;
1311 handle->url = GNUNET_strdup (rest_handle->url);
1312 if (handle->url[strlen (handle->url) - 1] == '/')
1313 handle->url[strlen (handle->url) - 1] = '\0';
1314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1316 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &init_egos, handle);
1318 handle->timeout_task =
1319 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_error, handle);
1321 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1326 * Entry point for the plugin.
1328 * @param cls Config info
1329 * @return NULL on error, otherwise the plugin context
1332 libgnunet_plugin_rest_identity_init (void *cls)
1334 static struct Plugin plugin;
1335 struct GNUNET_REST_Plugin *api;
1338 if (NULL != plugin.cfg)
1339 return NULL; /* can only initialize once! */
1340 memset (&plugin, 0, sizeof(struct Plugin));
1342 api = GNUNET_new (struct GNUNET_REST_Plugin);
1344 api->name = GNUNET_REST_API_NS_IDENTITY;
1345 api->process_request = &rest_process_request;
1346 GNUNET_asprintf (&allow_methods,
1347 "%s, %s, %s, %s, %s",
1348 MHD_HTTP_METHOD_GET,
1349 MHD_HTTP_METHOD_POST,
1350 MHD_HTTP_METHOD_PUT,
1351 MHD_HTTP_METHOD_DELETE,
1352 MHD_HTTP_METHOD_OPTIONS);
1354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Identity REST API initialized\n"));
1360 * Exit point from the plugin.
1362 * @param cls the plugin context (as returned by "init")
1363 * @return always NULL
1366 libgnunet_plugin_rest_identity_done (void *cls)
1368 struct GNUNET_REST_Plugin *api = cls;
1369 struct Plugin *plugin = api->cls;
1373 GNUNET_free_non_null (allow_methods);
1375 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n");
1380 /* end of plugin_rest_identity.c */