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
257 * Cleanup lookup handle
258 * @param handle Handle to clean up
261 cleanup_handle (void *cls)
263 struct RequestHandle *handle = cls;
264 struct EgoEntry *ego_entry;
265 struct EgoEntry *ego_tmp;
267 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
268 if (NULL != handle->timeout_task)
270 GNUNET_SCHEDULER_cancel (handle->timeout_task);
271 handle->timeout_task = NULL;
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);
283 for (ego_entry = handle->ego_head;
287 ego_entry = ego_entry->next;
288 GNUNET_free(ego_tmp->identifier);
289 GNUNET_free(ego_tmp->keystring);
290 GNUNET_free(ego_tmp);
297 * Task run on errors. Reports an error and cleans up everything.
299 * @param cls the `struct RequestHandle`
304 struct RequestHandle *handle = cls;
305 struct MHD_Response *resp;
306 json_t *json_error = json_object();
309 if (NULL == handle->emsg)
310 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_ERROR_UNKNOWN);
312 json_object_set_new(json_error,"error", json_string(handle->emsg));
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);
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
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
336 get_egoentry(struct RequestHandle *handle, char* pubkey, char *name)
338 struct EgoEntry *ego_entry;
341 for (ego_entry = handle->ego_head;
343 ego_entry = ego_entry->next)
345 if (0 != strcasecmp (pubkey, ego_entry->keystring))
352 for (ego_entry = handle->ego_head;
354 ego_entry = ego_entry->next)
356 if (0 != strcasecmp (name, ego_entry->identifier))
366 * Callback for GET Request with subsystem
368 * @param cls the RequestHandle
369 * @param ego the Ego found
370 * @param ctx the context
371 * @param name the id of the ego
374 ego_get_for_subsystem (void *cls,
375 struct GNUNET_IDENTITY_Ego *ego,
379 struct RequestHandle *handle = cls;
380 struct MHD_Response *resp;
381 struct GNUNET_CRYPTO_EcdsaPublicKey public_key;
384 char *public_key_string;
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);
394 GNUNET_IDENTITY_ego_get_public_key(ego,&public_key);
395 public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string(&public_key);
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,
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);
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);
418 * Handle identity GET request for subsystem
420 * @param con_handle the connection handle
422 * @param cls the RequestHandle
425 ego_get_subsystem (struct GNUNET_REST_RequestHandle *con_handle,
429 struct RequestHandle *handle = cls;
432 if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url))
434 handle->emsg = GNUNET_strdup("Missing subsystem name");
435 GNUNET_SCHEDULER_add_now (&do_error, handle);
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);
443 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
445 &ego_get_for_subsystem,
448 if (NULL == handle->op)
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);
459 * Handle identity GET request - responds with all identities
461 * @param con_handle the connection handle
463 * @param cls the RequestHandle
466 ego_get_all (struct GNUNET_REST_RequestHandle *con_handle,
470 struct RequestHandle *handle = cls;
471 struct EgoEntry *ego_entry;
472 struct MHD_Response *resp;
477 json_root = json_array ();
479 for (ego_entry = handle->ego_head;
480 NULL != ego_entry; ego_entry = ego_entry->next)
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);
493 if ((size_t) 0 == json_array_size (json_root))
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);
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);
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);
514 * Responds with the ego_entry identity
516 * @param handle the struct RequestHandle
517 * @param ego_entry the struct EgoEntry for the response
520 ego_get_response (struct RequestHandle *handle, struct EgoEntry *ego_entry)
522 struct MHD_Response *resp;
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));
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);
539 json_decref (json_ego);
540 GNUNET_free(result_str);
541 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
546 * Handle identity GET request with a public key
548 * @param con_handle the connection handle
550 * @param cls the RequestHandle
553 ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
557 struct RequestHandle *handle = cls;
558 struct EgoEntry *ego_entry;
563 if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
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);
570 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1];
571 ego_entry = get_egoentry(handle, keystring, NULL);
573 if (NULL == ego_entry)
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);
581 ego_get_response(handle, ego_entry);
585 * Handle identity GET request with a name
587 * @param con_handle the connection handle
589 * @param cls the RequestHandle
592 ego_get_name (struct GNUNET_REST_RequestHandle *con_handle,
596 struct RequestHandle *handle = cls;
597 struct EgoEntry *ego_entry;
602 if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
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);
609 egoname = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1];
610 ego_entry = get_egoentry(handle, NULL, egoname);
612 if (NULL == ego_entry)
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);
620 ego_get_response(handle, ego_entry);
625 * Processing finished
627 * @param cls request handle
628 * @param emsg error message
631 do_finished (void *cls, const char *emsg)
633 struct RequestHandle *handle = cls;
634 struct MHD_Response *resp;
639 handle->emsg = GNUNET_strdup(emsg);
640 GNUNET_SCHEDULER_add_now (&do_error, handle);
643 if (0 == handle->response_code)
645 handle->response_code = MHD_HTTP_NO_CONTENT;
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);
654 * Processing edit ego with EgoEntry ego_entry
656 * @param handle the struct RequestHandle
657 * @param ego_entry the struct EgoEntry we want to edit
660 ego_edit (struct RequestHandle *handle, struct EgoEntry *ego_entry)
662 struct EgoEntry *ego_entry_tmp;
663 struct MHD_Response *resp;
667 char term_data[handle->data_size + 1];
671 if (0 >= handle->data_size)
673 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
674 GNUNET_SCHEDULER_add_now (&do_error, handle);
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);
684 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
685 GNUNET_SCHEDULER_add_now (&do_error, handle);
692 json_state = json_unpack(data_js,
694 GNUNET_REST_IDENTITY_PARAM_NEWNAME,
696 //Change name with pubkey or name identifier
700 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
701 GNUNET_SCHEDULER_add_now (&do_error, handle);
702 json_decref (data_js);
708 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
709 GNUNET_SCHEDULER_add_now (&do_error, handle);
710 json_decref (data_js);
714 if (0 >= strlen (newname))
716 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
717 GNUNET_SCHEDULER_add_now (&do_error, handle);
718 json_decref (data_js);
722 ego_entry_tmp = get_egoentry (handle, NULL, newname);
723 if (NULL != ego_entry_tmp)
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);
732 handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
733 ego_entry->identifier,
737 if (NULL == handle->op)
739 handle->emsg = GNUNET_strdup("Rename failed");
740 GNUNET_SCHEDULER_add_now (&do_error, handle);
741 json_decref (data_js);
744 json_decref (data_js);
751 * Handle identity PUT request with public key
753 * @param con_handle the connection handle
755 * @param cls the RequestHandle
758 ego_edit_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
762 struct RequestHandle *handle = cls;
763 struct EgoEntry *ego_entry;
768 if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
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);
775 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1];
776 ego_entry = get_egoentry(handle, keystring, NULL);
778 if (NULL == ego_entry)
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);
786 ego_edit(handle,ego_entry);
790 * Handle identity PUT request with name
792 * @param con_handle the connection handle
794 * @param cls the RequestHandle
797 ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle,
801 struct RequestHandle *handle = cls;
802 struct EgoEntry *ego_entry;
807 if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
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);
814 name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1];
815 ego_entry = get_egoentry(handle, NULL, name);
817 if (NULL == ego_entry)
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);
825 ego_edit(handle,ego_entry);
829 * Handle identity subsystem PUT request with name
831 * @param con_handle the connection handle
833 * @param cls the RequestHandle
836 ego_edit_subsystem (struct GNUNET_REST_RequestHandle *con_handle,
840 struct RequestHandle *handle = cls;
841 struct EgoEntry *ego_entry;
846 char term_data[handle->data_size + 1];
851 if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url))
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);
858 name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM)+1];
859 ego_entry = get_egoentry(handle, NULL, name);
861 if (NULL == ego_entry)
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);
870 if (0 >= handle->data_size)
872 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
873 GNUNET_SCHEDULER_add_now (&do_error, handle);
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);
883 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
884 GNUNET_SCHEDULER_add_now (&do_error, handle);
891 json_state = json_unpack(data_js,
893 GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM,
895 //Change subsystem with pubkey or name identifier
898 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
899 GNUNET_SCHEDULER_add_now (&do_error, handle);
900 json_decref (data_js);
904 if (NULL == newsubsys)
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 (0 >= strlen (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 handle->response_code = MHD_HTTP_NO_CONTENT;
921 handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
926 if (NULL == handle->op)
928 handle->emsg = GNUNET_strdup("Setting subsystem failed");
929 GNUNET_SCHEDULER_add_now (&do_error, handle);
932 json_decref (data_js);
938 * Handle identity POST request
940 * @param con_handle the connection handle
942 * @param cls the RequestHandle
945 ego_create (struct GNUNET_REST_RequestHandle *con_handle,
949 struct RequestHandle *handle = cls;
950 struct EgoEntry *ego_entry;
951 struct MHD_Response *resp;
955 int json_unpack_state;
956 char term_data[handle->data_size + 1];
958 if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
960 GNUNET_SCHEDULER_add_now (&do_error, handle);
964 if (0 >= handle->data_size)
966 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
967 GNUNET_SCHEDULER_add_now (&do_error, handle);
970 term_data[handle->data_size] = '\0';
971 GNUNET_memcpy(term_data, handle->data, handle->data_size);
972 data_js = json_loads (term_data,
977 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
978 GNUNET_SCHEDULER_add_now (&do_error, handle);
979 json_decref (data_js);
982 json_unpack_state = 0;
983 json_unpack_state = json_unpack(data_js,
985 GNUNET_REST_IDENTITY_PARAM_NAME,
987 if (0 != json_unpack_state)
989 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
990 GNUNET_SCHEDULER_add_now (&do_error, handle);
991 json_decref (data_js);
997 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
998 GNUNET_SCHEDULER_add_now (&do_error, handle);
999 json_decref (data_js);
1002 if (0 >= strlen (egoname))
1004 json_decref (data_js);
1005 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
1006 GNUNET_SCHEDULER_add_now (&do_error, handle);
1009 GNUNET_STRINGS_utf8_tolower(egoname, egoname);
1010 for (ego_entry = handle->ego_head;
1011 NULL != ego_entry; ego_entry = ego_entry->next)
1013 if (0 == strcasecmp (egoname, ego_entry->identifier))
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);
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);
1030 * Handle identity DELETE request with public key
1032 * @param con_handle the connection handle
1033 * @param url the url
1034 * @param cls the RequestHandle
1037 ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
1041 struct RequestHandle *handle = cls;
1042 struct EgoEntry *ego_entry;
1047 if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
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);
1054 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1];
1055 ego_entry = get_egoentry(handle, keystring, NULL);
1057 if (NULL == ego_entry)
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);
1065 handle->response_code = MHD_HTTP_NO_CONTENT;
1066 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
1067 ego_entry->identifier,
1074 * Handle identity DELETE request with name
1076 * @param con_handle the connection handle
1077 * @param url the url
1078 * @param cls the RequestHandle
1081 ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle,
1085 struct RequestHandle *handle = cls;
1086 struct EgoEntry *ego_entry;
1091 if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
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);
1098 name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1];
1099 ego_entry = get_egoentry(handle, NULL, name);
1101 if (NULL == ego_entry)
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);
1109 handle->response_code = MHD_HTTP_NO_CONTENT;
1110 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
1111 ego_entry->identifier,
1118 * Respond to OPTIONS request
1120 * @param con_handle the connection handle
1121 * @param url the url
1122 * @param cls the RequestHandle
1125 options_cont (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
1128 struct MHD_Response *resp;
1129 struct RequestHandle *handle = cls;
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);
1140 * Handle rest request
1142 * @param handle the request handle
1145 init_cont (struct RequestHandle *handle)
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
1164 == GNUNET_REST_handle_request (handle->rest_handle, handlers, &err,
1167 handle->response_code = err.error_code;
1168 GNUNET_SCHEDULER_add_now (&do_error, handle);
1173 * If listing is enabled, prints information about the egos.
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.
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).
1189 * When an identity is renamed, this function is called with the
1190 * (known) ego but the NEW identifier.
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
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
1206 init_egos (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx,
1207 const char *identifier)
1209 struct RequestHandle *handle = cls;
1210 struct EgoEntry *ego_entry;
1211 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1213 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1215 handle->state = ID_REST_STATE_POST_INIT;
1219 if (ID_REST_STATE_INIT == handle->state)
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,
1232 * Function processing the REST call
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
1243 rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1244 GNUNET_REST_ResultProcessor proc, void *proc_cls)
1246 struct RequestHandle *handle = GNUNET_new(struct RequestHandle);
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;
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");
1261 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &init_egos, handle);
1263 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1266 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1270 * Entry point for the plugin.
1272 * @param cls Config info
1273 * @return NULL on error, otherwise the plugin context
1276 libgnunet_plugin_rest_identity_init (void *cls)
1278 static struct Plugin plugin;
1279 struct GNUNET_REST_Plugin *api;
1282 if (NULL != plugin.cfg)
1283 return NULL; /* can only initialize once! */
1284 memset (&plugin, 0, sizeof(struct Plugin));
1286 api = GNUNET_new(struct GNUNET_REST_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);
1297 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Identity REST API initialized\n"));
1302 * Exit point from the plugin.
1304 * @param cls the plugin context (as returned by "init")
1305 * @return always NULL
1308 libgnunet_plugin_rest_identity_done (void *cls)
1310 struct GNUNET_REST_Plugin *api = cls;
1311 struct Plugin *plugin = api->cls;
1314 GNUNET_free_non_null(allow_methods);
1316 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n");
1320 /* end of plugin_rest_identity.c */