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_ALL "/identity/all"
45 * Identity Namespace with public key specifier
47 #define GNUNET_REST_API_NS_IDENTITY_PUBKEY "/identity/pubkey"
50 * Identity Namespace with public key specifier
52 #define GNUNET_REST_API_NS_IDENTITY_NAME "/identity/name"
55 * Identity Subsystem Namespace
57 #define GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM "/identity/subsystem"
60 * Parameter public key
62 #define GNUNET_REST_IDENTITY_PARAM_PUBKEY "pubkey"
67 #define GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM "subsystem"
72 #define GNUNET_REST_IDENTITY_PARAM_NAME "name"
77 #define GNUNET_REST_IDENTITY_PARAM_NEWNAME "newname"
80 * Error message Unknown Error
82 #define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error"
85 * Error message No identity found
87 #define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found"
90 * Error message Missing identity name
92 #define GNUNET_REST_IDENTITY_MISSING_NAME "Missing identity name"
95 * Error message Missing identity name
97 #define GNUNET_REST_IDENTITY_MISSING_PUBKEY "Missing identity public key"
100 * Error message No data
102 #define GNUNET_REST_ERROR_NO_DATA "No data"
105 * Error message Data invalid
107 #define GNUNET_REST_ERROR_DATA_INVALID "Data invalid"
110 * State while collecting all egos
112 #define ID_REST_STATE_INIT 0
115 * Done collecting egos
117 #define ID_REST_STATE_POST_INIT 1
120 * The configuration handle
122 const struct GNUNET_CONFIGURATION_Handle *cfg;
125 * HTTP methods allows for this plugin
127 static char *allow_methods;
130 * @brief struct returned by the initialization function of the plugin
134 const struct GNUNET_CONFIGURATION_Handle *cfg;
145 struct EgoEntry *next;
150 struct EgoEntry *prev;
165 struct GNUNET_IDENTITY_Ego *ego;
174 * The data from the REST request
179 * The name to look up
184 * the length of the REST data
192 struct EgoEntry *ego_head;
197 struct EgoEntry *ego_tail;
200 * The processing state
205 * Handle to Identity service.
207 struct GNUNET_IDENTITY_Handle *identity_handle;
212 struct GNUNET_IDENTITY_Operation *op;
217 struct GNUNET_REST_RequestHandle *rest_handle;
220 * Desired timeout for the lookup (default is no timeout).
222 struct GNUNET_TIME_Relative timeout;
225 * ID of a task associated with the resolution process.
227 struct GNUNET_SCHEDULER_Task *timeout_task;
230 * The plugin result processor
232 GNUNET_REST_ResultProcessor proc;
235 * The closure of the result processor
245 * Error response message
256 * Cleanup lookup handle
257 * @param handle Handle to clean up
260 cleanup_handle (void *cls)
262 struct RequestHandle *handle = cls;
263 struct EgoEntry *ego_entry;
264 struct EgoEntry *ego_tmp;
266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
267 if (NULL != handle->timeout_task)
269 GNUNET_SCHEDULER_cancel (handle->timeout_task);
270 handle->timeout_task = NULL;
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);
282 for (ego_entry = handle->ego_head; NULL != 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);
291 GNUNET_free (handle);
296 * Task run on errors. Reports an error and cleans up everything.
298 * @param cls the `struct RequestHandle`
303 struct RequestHandle *handle = cls;
304 struct MHD_Response *resp;
305 json_t *json_error = json_object ();
308 if (NULL == handle->emsg)
309 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_ERROR_UNKNOWN);
311 json_object_set_new (json_error, "error", json_string (handle->emsg));
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);
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
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
334 get_egoentry (struct RequestHandle *handle, char *pubkey, char *name)
336 struct EgoEntry *ego_entry;
340 for (ego_entry = handle->ego_head; NULL != ego_entry;
341 ego_entry = ego_entry->next)
343 if (0 != strcasecmp (pubkey, ego_entry->keystring))
350 for (ego_entry = handle->ego_head; NULL != ego_entry;
351 ego_entry = ego_entry->next)
353 if (0 != strcasecmp (name, ego_entry->identifier))
363 * Callback for GET Request with subsystem
365 * @param cls the RequestHandle
366 * @param ego the Ego found
367 * @param ctx the context
368 * @param name the id of the ego
371 ego_get_for_subsystem (void *cls,
372 struct GNUNET_IDENTITY_Ego *ego,
376 struct RequestHandle *handle = cls;
377 struct MHD_Response *resp;
378 struct GNUNET_CRYPTO_EcdsaPublicKey public_key;
381 char *public_key_string;
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);
391 GNUNET_IDENTITY_ego_get_public_key (ego, &public_key);
392 public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string (&public_key);
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,
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);
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);
416 * Handle identity GET request for subsystem
418 * @param con_handle the connection handle
420 * @param cls the RequestHandle
423 ego_get_subsystem (struct GNUNET_REST_RequestHandle *con_handle,
427 struct RequestHandle *handle = cls;
430 if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url))
432 handle->emsg = GNUNET_strdup ("Missing subsystem name");
433 GNUNET_SCHEDULER_add_now (&do_error, handle);
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);
440 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
442 &ego_get_for_subsystem,
445 if (NULL == handle->op)
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);
456 * Handle identity GET request - responds with all identities
458 * @param con_handle the connection handle
460 * @param cls the RequestHandle
463 ego_get_all (struct GNUNET_REST_RequestHandle *con_handle,
467 struct RequestHandle *handle = cls;
468 struct EgoEntry *ego_entry;
469 struct MHD_Response *resp;
474 json_root = json_array ();
476 for (ego_entry = handle->ego_head; NULL != ego_entry;
477 ego_entry = ego_entry->next)
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);
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);
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);
502 * Responds with the ego_entry identity
504 * @param handle the struct RequestHandle
505 * @param ego_entry the struct EgoEntry for the response
508 ego_get_response (struct RequestHandle *handle, struct EgoEntry *ego_entry)
510 struct MHD_Response *resp;
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));
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);
527 json_decref (json_ego);
528 GNUNET_free (result_str);
529 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
534 * Handle identity GET request with a public key
536 * @param con_handle the connection handle
538 * @param cls the RequestHandle
541 ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
545 struct RequestHandle *handle = cls;
546 struct EgoEntry *ego_entry;
551 if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
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);
558 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) + 1];
559 ego_entry = get_egoentry (handle, keystring, NULL);
561 if (NULL == ego_entry)
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);
569 ego_get_response (handle, ego_entry);
574 * Handle identity GET request with a name
576 * @param con_handle the connection handle
578 * @param cls the RequestHandle
581 ego_get_name (struct GNUNET_REST_RequestHandle *con_handle,
585 struct RequestHandle *handle = cls;
586 struct EgoEntry *ego_entry;
591 if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
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);
598 egoname = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME) + 1];
599 ego_entry = get_egoentry (handle, NULL, egoname);
601 if (NULL == ego_entry)
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);
609 ego_get_response (handle, ego_entry);
614 * Processing finished
616 * @param cls request handle
617 * @param emsg error message
620 do_finished (void *cls, const char *emsg)
622 struct RequestHandle *handle = cls;
623 struct MHD_Response *resp;
628 handle->emsg = GNUNET_strdup (emsg);
629 GNUNET_SCHEDULER_add_now (&do_error, handle);
632 if (0 == handle->response_code)
634 handle->response_code = MHD_HTTP_NO_CONTENT;
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);
643 * Processing finished, when creating an ego.
645 * @param cls request handle
646 * @param private key of the ego, or NULL on error
647 * @param emsg error message
650 do_finished_create (void *cls,
651 const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
654 struct RequestHandle *handle = cls;
657 do_finished (handle, emsg);
662 * Processing edit ego with EgoEntry ego_entry
664 * @param handle the struct RequestHandle
665 * @param ego_entry the struct EgoEntry we want to edit
668 ego_edit (struct RequestHandle *handle, struct EgoEntry *ego_entry)
670 struct EgoEntry *ego_entry_tmp;
671 struct MHD_Response *resp;
675 char term_data[handle->data_size + 1];
679 if (0 >= handle->data_size)
681 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
682 GNUNET_SCHEDULER_add_now (&do_error, handle);
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);
692 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
693 GNUNET_SCHEDULER_add_now (&do_error, handle);
700 json_state = json_unpack (data_js,
702 GNUNET_REST_IDENTITY_PARAM_NEWNAME,
704 // Change name with pubkey or name identifier
707 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
708 GNUNET_SCHEDULER_add_now (&do_error, handle);
709 json_decref (data_js);
715 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
716 GNUNET_SCHEDULER_add_now (&do_error, handle);
717 json_decref (data_js);
721 if (0 >= strlen (newname))
723 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
724 GNUNET_SCHEDULER_add_now (&do_error, handle);
725 json_decref (data_js);
729 ego_entry_tmp = get_egoentry (handle, NULL, newname);
730 if (NULL != ego_entry_tmp)
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);
739 handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
740 ego_entry->identifier,
744 if (NULL == handle->op)
746 handle->emsg = GNUNET_strdup ("Rename failed");
747 GNUNET_SCHEDULER_add_now (&do_error, handle);
748 json_decref (data_js);
751 json_decref (data_js);
757 * Handle identity PUT request with public key
759 * @param con_handle the connection handle
761 * @param cls the RequestHandle
764 ego_edit_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
768 struct RequestHandle *handle = cls;
769 struct EgoEntry *ego_entry;
774 if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
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);
781 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) + 1];
782 ego_entry = get_egoentry (handle, keystring, NULL);
784 if (NULL == ego_entry)
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);
792 ego_edit (handle, ego_entry);
797 * Handle identity PUT request with name
799 * @param con_handle the connection handle
801 * @param cls the RequestHandle
804 ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle,
808 struct RequestHandle *handle = cls;
809 struct EgoEntry *ego_entry;
814 if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
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);
821 name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME) + 1];
822 ego_entry = get_egoentry (handle, NULL, name);
824 if (NULL == ego_entry)
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);
832 ego_edit (handle, ego_entry);
837 * Handle identity subsystem PUT request with name
839 * @param con_handle the connection handle
841 * @param cls the RequestHandle
844 ego_edit_subsystem (struct GNUNET_REST_RequestHandle *con_handle,
848 struct RequestHandle *handle = cls;
849 struct EgoEntry *ego_entry;
854 char term_data[handle->data_size + 1];
859 if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url))
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);
866 name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) + 1];
867 ego_entry = get_egoentry (handle, NULL, name);
869 if (NULL == ego_entry)
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);
878 if (0 >= handle->data_size)
880 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
881 GNUNET_SCHEDULER_add_now (&do_error, handle);
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);
891 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
892 GNUNET_SCHEDULER_add_now (&do_error, handle);
899 json_state = json_unpack (data_js,
901 GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM,
903 // Change subsystem with pubkey or name identifier
906 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
907 GNUNET_SCHEDULER_add_now (&do_error, handle);
908 json_decref (data_js);
912 if (NULL == newsubsys)
914 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
915 GNUNET_SCHEDULER_add_now (&do_error, handle);
916 json_decref (data_js);
920 if (0 >= strlen (newsubsys))
922 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
923 GNUNET_SCHEDULER_add_now (&do_error, handle);
924 json_decref (data_js);
928 handle->response_code = MHD_HTTP_NO_CONTENT;
929 handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
934 if (NULL == handle->op)
936 handle->emsg = GNUNET_strdup ("Setting subsystem failed");
937 GNUNET_SCHEDULER_add_now (&do_error, handle);
940 json_decref (data_js);
946 * Handle identity POST request
948 * @param con_handle the connection handle
950 * @param cls the RequestHandle
953 ego_create (struct GNUNET_REST_RequestHandle *con_handle,
957 struct RequestHandle *handle = cls;
958 struct EgoEntry *ego_entry;
959 struct MHD_Response *resp;
963 int json_unpack_state;
964 char term_data[handle->data_size + 1];
966 if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
968 GNUNET_SCHEDULER_add_now (&do_error, handle);
972 if (0 >= handle->data_size)
974 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
975 GNUNET_SCHEDULER_add_now (&do_error, handle);
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);
983 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
984 GNUNET_SCHEDULER_add_now (&do_error, handle);
985 json_decref (data_js);
988 json_unpack_state = 0;
990 json_unpack (data_js, "{s:s!}", GNUNET_REST_IDENTITY_PARAM_NAME, &egoname);
991 if (0 != json_unpack_state)
993 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
994 GNUNET_SCHEDULER_add_now (&do_error, handle);
995 json_decref (data_js);
1001 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
1002 GNUNET_SCHEDULER_add_now (&do_error, handle);
1003 json_decref (data_js);
1006 if (0 >= strlen (egoname))
1008 json_decref (data_js);
1009 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
1010 GNUNET_SCHEDULER_add_now (&do_error, handle);
1013 GNUNET_STRINGS_utf8_tolower (egoname, egoname);
1014 for (ego_entry = handle->ego_head; NULL != ego_entry;
1015 ego_entry = ego_entry->next)
1017 if (0 == strcasecmp (egoname, ego_entry->identifier))
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);
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,
1031 &do_finished_create,
1037 * Handle identity DELETE request with public key
1039 * @param con_handle the connection handle
1040 * @param url the url
1041 * @param cls the RequestHandle
1044 ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
1048 struct RequestHandle *handle = cls;
1049 struct EgoEntry *ego_entry;
1054 if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
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);
1061 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) + 1];
1062 ego_entry = get_egoentry (handle, keystring, NULL);
1064 if (NULL == ego_entry)
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);
1072 handle->response_code = MHD_HTTP_NO_CONTENT;
1073 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
1074 ego_entry->identifier,
1081 * Handle identity DELETE request with name
1083 * @param con_handle the connection handle
1084 * @param url the url
1085 * @param cls the RequestHandle
1088 ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle,
1092 struct RequestHandle *handle = cls;
1093 struct EgoEntry *ego_entry;
1098 if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
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);
1105 name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME) + 1];
1106 ego_entry = get_egoentry (handle, NULL, name);
1108 if (NULL == ego_entry)
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);
1116 handle->response_code = MHD_HTTP_NO_CONTENT;
1117 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
1118 ego_entry->identifier,
1125 * Respond to OPTIONS request
1127 * @param con_handle the connection handle
1128 * @param url the url
1129 * @param cls the RequestHandle
1132 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1136 struct MHD_Response *resp;
1137 struct RequestHandle *handle = cls;
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);
1149 * Handle rest request
1151 * @param handle the request handle
1154 init_cont (struct RequestHandle *handle)
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,
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,
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,
1179 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont },
1180 GNUNET_REST_HANDLER_END };
1183 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1185 handle->response_code = err.error_code;
1186 GNUNET_SCHEDULER_add_now (&do_error, handle);
1192 * If listing is enabled, prints information about the egos.
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.
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).
1208 * When an identity is renamed, this function is called with the
1209 * (known) ego but the NEW identifier.
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
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
1225 init_egos (void *cls,
1226 struct GNUNET_IDENTITY_Ego *ego,
1228 const char *identifier)
1230 struct RequestHandle *handle = cls;
1231 struct EgoEntry *ego_entry;
1232 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1234 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1236 handle->state = ID_REST_STATE_POST_INIT;
1240 if (ID_REST_STATE_INIT == handle->state)
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,
1252 // Check if ego exists
1253 for (ego_entry = handle->ego_head; NULL != ego_entry;)
1255 struct EgoEntry *tmp = ego_entry;
1256 ego_entry = ego_entry->next;
1257 if (ego != tmp->ego)
1260 if (NULL == identifier)
1262 GNUNET_CONTAINER_DLL_remove (handle->ego_head,
1265 GNUNET_free (tmp->keystring);
1266 GNUNET_free (tmp->identifier);
1272 GNUNET_free (tmp->identifier);
1273 tmp->identifier = GNUNET_strdup (identifier);
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,
1291 * Function processing the REST call
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
1302 rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1303 GNUNET_REST_ResultProcessor proc,
1306 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
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;
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");
1321 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &init_egos, handle);
1323 handle->timeout_task =
1324 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_error, handle);
1326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1331 * Entry point for the plugin.
1333 * @param cls Config info
1334 * @return NULL on error, otherwise the plugin context
1337 libgnunet_plugin_rest_identity_init (void *cls)
1339 static struct Plugin plugin;
1340 struct GNUNET_REST_Plugin *api;
1343 if (NULL != plugin.cfg)
1344 return NULL; /* can only initialize once! */
1345 memset (&plugin, 0, sizeof(struct Plugin));
1347 api = GNUNET_new (struct GNUNET_REST_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);
1359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Identity REST API initialized\n"));
1365 * Exit point from the plugin.
1367 * @param cls the plugin context (as returned by "init")
1368 * @return always NULL
1371 libgnunet_plugin_rest_identity_done (void *cls)
1373 struct GNUNET_REST_Plugin *api = cls;
1374 struct Plugin *plugin = api->cls;
1378 GNUNET_free_non_null (allow_methods);
1380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n");
1385 /* end of plugin_rest_identity.c */