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/>.
19 * @author Martin Schanzenbach
20 * @author Philippe Buschmann
21 * @file identity/plugin_rest_identity.c
22 * @brief GNUnet Identity REST plugin
26 #include "gnunet_rest_plugin.h"
27 #include "gnunet_identity_service.h"
28 #include "gnunet_rest_lib.h"
29 #include "microhttpd.h"
35 #define GNUNET_REST_API_NS_IDENTITY "/identity"
38 * Identity Namespace with public key specifier
40 #define GNUNET_REST_API_NS_IDENTITY_ALL "/identity/all"
43 * Identity Namespace with public key specifier
45 #define GNUNET_REST_API_NS_IDENTITY_PUBKEY "/identity/pubkey"
48 * Identity Namespace with public key specifier
50 #define GNUNET_REST_API_NS_IDENTITY_NAME "/identity/name"
53 * Identity Subsystem Namespace
55 #define GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM "/identity/subsystem"
58 * Parameter public key
60 #define GNUNET_REST_IDENTITY_PARAM_PUBKEY "pubkey"
65 #define GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM "subsystem"
70 #define GNUNET_REST_IDENTITY_PARAM_NAME "name"
75 #define GNUNET_REST_IDENTITY_PARAM_NEWNAME "newname"
78 * Error message Unknown Error
80 #define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error"
83 * Error message No identity found
85 #define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found"
88 * Error message Missing identity name
90 #define GNUNET_REST_IDENTITY_MISSING_NAME "Missing identity name"
93 * Error message Missing identity name
95 #define GNUNET_REST_IDENTITY_MISSING_PUBKEY "Missing identity public key"
98 * Error message No data
100 #define GNUNET_REST_ERROR_NO_DATA "No data"
103 * Error message Data invalid
105 #define GNUNET_REST_ERROR_DATA_INVALID "Data invalid"
108 * State while collecting all egos
110 #define ID_REST_STATE_INIT 0
113 * Done collecting egos
115 #define ID_REST_STATE_POST_INIT 1
118 * The configuration handle
120 const struct GNUNET_CONFIGURATION_Handle *cfg;
123 * HTTP methods allows for this plugin
125 static char* allow_methods;
128 * @brief struct returned by the initialization function of the plugin
132 const struct GNUNET_CONFIGURATION_Handle *cfg;
143 struct EgoEntry *next;
148 struct EgoEntry *prev;
163 struct GNUNET_IDENTITY_Ego *ego;
172 * The data from the REST request
177 * The name to look up
182 * the length of the REST data
190 struct EgoEntry *ego_head;
195 struct EgoEntry *ego_tail;
198 * The processing state
203 * Handle to Identity service.
205 struct GNUNET_IDENTITY_Handle *identity_handle;
210 struct GNUNET_IDENTITY_Operation *op;
215 struct GNUNET_REST_RequestHandle *rest_handle;
218 * Desired timeout for the lookup (default is no timeout).
220 struct GNUNET_TIME_Relative timeout;
223 * ID of a task associated with the resolution process.
225 struct GNUNET_SCHEDULER_Task *timeout_task;
228 * The plugin result processor
230 GNUNET_REST_ResultProcessor proc;
233 * The closure of the result processor
243 * Error response message
255 * Cleanup lookup handle
256 * @param handle Handle to clean up
259 cleanup_handle (void *cls)
261 struct RequestHandle *handle = cls;
262 struct EgoEntry *ego_entry;
263 struct EgoEntry *ego_tmp;
265 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
266 if (NULL != handle->timeout_task)
268 GNUNET_SCHEDULER_cancel (handle->timeout_task);
269 handle->timeout_task = NULL;
272 if (NULL != handle->url)
273 GNUNET_free(handle->url);
274 if (NULL != handle->emsg)
275 GNUNET_free(handle->emsg);
276 if (NULL != handle->name)
277 GNUNET_free (handle->name);
278 if (NULL != handle->identity_handle)
279 GNUNET_IDENTITY_disconnect (handle->identity_handle);
281 for (ego_entry = handle->ego_head;
285 ego_entry = ego_entry->next;
286 GNUNET_free(ego_tmp->identifier);
287 GNUNET_free(ego_tmp->keystring);
288 GNUNET_free(ego_tmp);
295 * Task run on errors. Reports an error and cleans up everything.
297 * @param cls the `struct RequestHandle`
302 struct RequestHandle *handle = cls;
303 struct MHD_Response *resp;
304 json_t *json_error = json_object();
307 if (NULL == handle->emsg)
308 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_ERROR_UNKNOWN);
310 json_object_set_new(json_error,"error", json_string(handle->emsg));
312 if (0 == handle->response_code)
313 handle->response_code = MHD_HTTP_OK;
314 response = json_dumps (json_error, 0);
315 resp = GNUNET_REST_create_response (response);
316 handle->proc (handle->proc_cls, resp, handle->response_code);
317 json_decref(json_error);
318 GNUNET_free(response);
319 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;
339 for (ego_entry = handle->ego_head;
341 ego_entry = ego_entry->next)
343 if (0 != strcasecmp (pubkey, ego_entry->keystring))
350 for (ego_entry = handle->ego_head;
352 ego_entry = ego_entry->next)
354 if (0 != strcasecmp (name, ego_entry->identifier))
364 * Callback for GET Request with subsystem
366 * @param cls the RequestHandle
367 * @param ego the Ego found
368 * @param ctx the context
369 * @param name the id of the ego
372 ego_get_for_subsystem (void *cls,
373 struct GNUNET_IDENTITY_Ego *ego,
377 struct RequestHandle *handle = cls;
378 struct MHD_Response *resp;
379 struct GNUNET_CRYPTO_EcdsaPublicKey public_key;
382 char *public_key_string;
386 handle->response_code = MHD_HTTP_NOT_FOUND;
387 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
388 GNUNET_SCHEDULER_add_now (&do_error, handle);
392 GNUNET_IDENTITY_ego_get_public_key(ego,&public_key);
393 public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string(&public_key);
395 // create json with subsystem identity
396 json_root = json_object ();
397 json_object_set_new (json_root,
398 GNUNET_REST_IDENTITY_PARAM_PUBKEY,
399 json_string(public_key_string));
400 json_object_set_new (json_root,
401 GNUNET_REST_IDENTITY_PARAM_NAME,
404 result_str = json_dumps (json_root, 0);
405 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
406 resp = GNUNET_REST_create_response (result_str);
408 json_decref (json_root);
409 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
410 GNUNET_free(result_str);
411 GNUNET_free(public_key_string);
412 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 (
437 GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) + 1];
438 //requested default identity of subsystem
439 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsystem);
441 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
443 &ego_get_for_subsystem,
446 if (NULL == handle->op)
448 handle->response_code = MHD_HTTP_NOT_FOUND;
449 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
450 GNUNET_SCHEDULER_add_now (&do_error, handle);
457 * Handle identity GET request - responds with all identities
459 * @param con_handle the connection handle
461 * @param cls the RequestHandle
464 ego_get_all (struct GNUNET_REST_RequestHandle *con_handle,
468 struct RequestHandle *handle = cls;
469 struct EgoEntry *ego_entry;
470 struct MHD_Response *resp;
475 json_root = json_array ();
477 for (ego_entry = handle->ego_head;
478 NULL != ego_entry; ego_entry = ego_entry->next)
480 json_ego = json_object ();
481 json_object_set_new (json_ego,
482 GNUNET_REST_IDENTITY_PARAM_PUBKEY,
483 json_string (ego_entry->keystring));
484 json_object_set_new (json_ego,
485 GNUNET_REST_IDENTITY_PARAM_NAME,
486 json_string (ego_entry->identifier));
487 json_array_append (json_root, json_ego);
488 json_decref (json_ego);
491 if ((size_t) 0 == json_array_size (json_root))
493 json_decref (json_root);
494 handle->response_code = MHD_HTTP_NOT_FOUND;
495 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
496 GNUNET_SCHEDULER_add_now (&do_error, handle);
500 result_str = json_dumps (json_root, 0);
501 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
502 resp = GNUNET_REST_create_response (result_str);
504 json_decref (json_root);
505 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
506 GNUNET_free(result_str);
507 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
512 * Responds with the ego_entry identity
514 * @param handle the struct RequestHandle
515 * @param ego_entry the struct EgoEntry for the response
518 ego_get_response (struct RequestHandle *handle, struct EgoEntry *ego_entry)
520 struct MHD_Response *resp;
524 json_ego = json_object ();
525 json_object_set_new (json_ego,
526 GNUNET_REST_IDENTITY_PARAM_PUBKEY,
527 json_string (ego_entry->keystring));
528 json_object_set_new (json_ego,
529 GNUNET_REST_IDENTITY_PARAM_NAME,
530 json_string (ego_entry->identifier));
532 result_str = json_dumps (json_ego, 0);
533 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
534 resp = GNUNET_REST_create_response (result_str);
535 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
537 json_decref (json_ego);
538 GNUNET_free(result_str);
539 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
544 * Handle identity GET request with a public key
546 * @param con_handle the connection handle
548 * @param cls the RequestHandle
551 ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
555 struct RequestHandle *handle = cls;
556 struct EgoEntry *ego_entry;
561 if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
563 handle->response_code = MHD_HTTP_NOT_FOUND;
564 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY);
565 GNUNET_SCHEDULER_add_now (&do_error, handle);
568 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1];
569 ego_entry = get_egoentry(handle, keystring, NULL);
571 if (NULL == ego_entry)
573 handle->response_code = MHD_HTTP_NOT_FOUND;
574 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
575 GNUNET_SCHEDULER_add_now (&do_error, handle);
579 ego_get_response(handle, ego_entry);
583 * Handle identity GET request with a name
585 * @param con_handle the connection handle
587 * @param cls the RequestHandle
590 ego_get_name (struct GNUNET_REST_RequestHandle *con_handle,
594 struct RequestHandle *handle = cls;
595 struct EgoEntry *ego_entry;
600 if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
602 handle->response_code = MHD_HTTP_NOT_FOUND;
603 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME);
604 GNUNET_SCHEDULER_add_now (&do_error, handle);
607 egoname = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1];
608 ego_entry = get_egoentry(handle, NULL, egoname);
610 if (NULL == ego_entry)
612 handle->response_code = MHD_HTTP_NOT_FOUND;
613 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
614 GNUNET_SCHEDULER_add_now (&do_error, handle);
618 ego_get_response(handle, ego_entry);
623 * Processing finished
625 * @param cls request handle
626 * @param emsg error message
629 do_finished (void *cls, const char *emsg)
631 struct RequestHandle *handle = cls;
632 struct MHD_Response *resp;
637 handle->emsg = GNUNET_strdup(emsg);
638 GNUNET_SCHEDULER_add_now (&do_error, handle);
641 if (0 == handle->response_code)
643 handle->response_code = MHD_HTTP_NO_CONTENT;
645 resp = GNUNET_REST_create_response (NULL);
646 handle->proc (handle->proc_cls, resp, handle->response_code);
647 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
652 * Processing edit ego with EgoEntry ego_entry
654 * @param handle the struct RequestHandle
655 * @param ego_entry the struct EgoEntry we want to edit
658 ego_edit (struct RequestHandle *handle, struct EgoEntry *ego_entry)
660 struct EgoEntry *ego_entry_tmp;
661 struct MHD_Response *resp;
665 char term_data[handle->data_size + 1];
669 if (0 >= handle->data_size)
671 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
672 GNUNET_SCHEDULER_add_now (&do_error, handle);
676 term_data[handle->data_size] = '\0';
677 GNUNET_memcpy(term_data, handle->data, handle->data_size);
678 data_js = json_loads (term_data,JSON_DECODE_ANY,&err);
682 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
683 GNUNET_SCHEDULER_add_now (&do_error, handle);
690 json_state = json_unpack(data_js,
692 GNUNET_REST_IDENTITY_PARAM_NEWNAME,
694 //Change name with pubkey or name identifier
698 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
699 GNUNET_SCHEDULER_add_now (&do_error, handle);
700 json_decref (data_js);
706 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
707 GNUNET_SCHEDULER_add_now (&do_error, handle);
708 json_decref (data_js);
712 if (0 >= strlen (newname))
714 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
715 GNUNET_SCHEDULER_add_now (&do_error, handle);
716 json_decref (data_js);
720 ego_entry_tmp = get_egoentry (handle, NULL, newname);
721 if (NULL != ego_entry_tmp)
723 //Ego with same name not allowed (even if its the ego we change)
724 resp = GNUNET_REST_create_response (NULL);
725 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
726 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
727 json_decref (data_js);
730 handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
731 ego_entry->identifier,
735 if (NULL == handle->op)
737 handle->emsg = GNUNET_strdup("Rename failed");
738 GNUNET_SCHEDULER_add_now (&do_error, handle);
739 json_decref (data_js);
742 json_decref (data_js);
749 * Handle identity PUT request with public key
751 * @param con_handle the connection handle
753 * @param cls the RequestHandle
756 ego_edit_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
760 struct RequestHandle *handle = cls;
761 struct EgoEntry *ego_entry;
766 if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
768 handle->response_code = MHD_HTTP_NOT_FOUND;
769 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY);
770 GNUNET_SCHEDULER_add_now (&do_error, handle);
773 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1];
774 ego_entry = get_egoentry(handle, keystring, NULL);
776 if (NULL == ego_entry)
778 handle->response_code = MHD_HTTP_NOT_FOUND;
779 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
780 GNUNET_SCHEDULER_add_now (&do_error, handle);
784 ego_edit(handle,ego_entry);
788 * Handle identity PUT request with name
790 * @param con_handle the connection handle
792 * @param cls the RequestHandle
795 ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle,
799 struct RequestHandle *handle = cls;
800 struct EgoEntry *ego_entry;
805 if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
807 handle->response_code = MHD_HTTP_NOT_FOUND;
808 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME);
809 GNUNET_SCHEDULER_add_now (&do_error, handle);
812 name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1];
813 ego_entry = get_egoentry(handle, NULL, name);
815 if (NULL == ego_entry)
817 handle->response_code = MHD_HTTP_NOT_FOUND;
818 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
819 GNUNET_SCHEDULER_add_now (&do_error, handle);
823 ego_edit(handle,ego_entry);
827 * Handle identity subsystem PUT request with name
829 * @param con_handle the connection handle
831 * @param cls the RequestHandle
834 ego_edit_subsystem (struct GNUNET_REST_RequestHandle *con_handle,
838 struct RequestHandle *handle = cls;
839 struct EgoEntry *ego_entry;
844 char term_data[handle->data_size + 1];
849 if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url))
851 handle->response_code = MHD_HTTP_NOT_FOUND;
852 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME);
853 GNUNET_SCHEDULER_add_now (&do_error, handle);
856 name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM)+1];
857 ego_entry = get_egoentry(handle, NULL, name);
859 if (NULL == ego_entry)
861 handle->response_code = MHD_HTTP_NOT_FOUND;
862 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
863 GNUNET_SCHEDULER_add_now (&do_error, handle);
868 if (0 >= handle->data_size)
870 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
871 GNUNET_SCHEDULER_add_now (&do_error, handle);
875 term_data[handle->data_size] = '\0';
876 GNUNET_memcpy(term_data, handle->data, handle->data_size);
877 data_js = json_loads (term_data,JSON_DECODE_ANY,&err);
881 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
882 GNUNET_SCHEDULER_add_now (&do_error, handle);
889 json_state = json_unpack(data_js,
891 GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM,
893 //Change subsystem with pubkey or name identifier
896 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
897 GNUNET_SCHEDULER_add_now (&do_error, handle);
898 json_decref (data_js);
902 if (NULL == newsubsys)
904 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
905 GNUNET_SCHEDULER_add_now (&do_error, handle);
906 json_decref (data_js);
910 if (0 >= strlen (newsubsys))
912 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
913 GNUNET_SCHEDULER_add_now (&do_error, handle);
914 json_decref (data_js);
918 handle->response_code = MHD_HTTP_NO_CONTENT;
919 handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
924 if (NULL == handle->op)
926 handle->emsg = GNUNET_strdup("Setting subsystem failed");
927 GNUNET_SCHEDULER_add_now (&do_error, handle);
930 json_decref (data_js);
936 * Handle identity POST request
938 * @param con_handle the connection handle
940 * @param cls the RequestHandle
943 ego_create (struct GNUNET_REST_RequestHandle *con_handle,
947 struct RequestHandle *handle = cls;
948 struct EgoEntry *ego_entry;
949 struct MHD_Response *resp;
953 int json_unpack_state;
954 char term_data[handle->data_size + 1];
956 if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
958 GNUNET_SCHEDULER_add_now (&do_error, handle);
962 if (0 >= handle->data_size)
964 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
965 GNUNET_SCHEDULER_add_now (&do_error, handle);
968 term_data[handle->data_size] = '\0';
969 GNUNET_memcpy(term_data, handle->data, handle->data_size);
970 data_js = json_loads (term_data,
975 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
976 GNUNET_SCHEDULER_add_now (&do_error, handle);
977 json_decref (data_js);
980 json_unpack_state = 0;
981 json_unpack_state = json_unpack(data_js,
983 GNUNET_REST_IDENTITY_PARAM_NAME,
985 if (0 != json_unpack_state)
987 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
988 GNUNET_SCHEDULER_add_now (&do_error, handle);
989 json_decref (data_js);
995 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
996 GNUNET_SCHEDULER_add_now (&do_error, handle);
997 json_decref (data_js);
1000 if (0 >= strlen (egoname))
1002 json_decref (data_js);
1003 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
1004 GNUNET_SCHEDULER_add_now (&do_error, handle);
1007 GNUNET_STRINGS_utf8_tolower(egoname, egoname);
1008 for (ego_entry = handle->ego_head;
1009 NULL != ego_entry; ego_entry = ego_entry->next)
1011 if (0 == strcasecmp (egoname, ego_entry->identifier))
1013 resp = GNUNET_REST_create_response (NULL);
1014 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
1015 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
1016 json_decref (data_js);
1020 handle->name = GNUNET_strdup(egoname);
1021 json_decref (data_js);
1022 handle->response_code = MHD_HTTP_CREATED;
1023 handle->op = GNUNET_IDENTITY_create (handle->identity_handle, handle->name,
1024 &do_finished, handle);
1028 * Handle identity DELETE request with public key
1030 * @param con_handle the connection handle
1031 * @param url the url
1032 * @param cls the RequestHandle
1035 ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
1039 struct RequestHandle *handle = cls;
1040 struct EgoEntry *ego_entry;
1045 if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
1047 handle->response_code = MHD_HTTP_NOT_FOUND;
1048 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY);
1049 GNUNET_SCHEDULER_add_now (&do_error, handle);
1052 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1];
1053 ego_entry = get_egoentry(handle, keystring, NULL);
1055 if (NULL == ego_entry)
1057 handle->response_code = MHD_HTTP_NOT_FOUND;
1058 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
1059 GNUNET_SCHEDULER_add_now (&do_error, handle);
1063 handle->response_code = MHD_HTTP_NO_CONTENT;
1064 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
1065 ego_entry->identifier,
1072 * Handle identity DELETE request with name
1074 * @param con_handle the connection handle
1075 * @param url the url
1076 * @param cls the RequestHandle
1079 ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle,
1083 struct RequestHandle *handle = cls;
1084 struct EgoEntry *ego_entry;
1089 if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
1091 handle->response_code = MHD_HTTP_NOT_FOUND;
1092 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME);
1093 GNUNET_SCHEDULER_add_now (&do_error, handle);
1096 name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1];
1097 ego_entry = get_egoentry(handle, NULL, name);
1099 if (NULL == ego_entry)
1101 handle->response_code = MHD_HTTP_NOT_FOUND;
1102 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
1103 GNUNET_SCHEDULER_add_now (&do_error, handle);
1107 handle->response_code = MHD_HTTP_NO_CONTENT;
1108 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
1109 ego_entry->identifier,
1116 * Respond to OPTIONS request
1118 * @param con_handle the connection handle
1119 * @param url the url
1120 * @param cls the RequestHandle
1123 options_cont (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
1126 struct MHD_Response *resp;
1127 struct RequestHandle *handle = cls;
1129 //For now, independent of path return all options
1130 resp = GNUNET_REST_create_response (NULL);
1131 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
1132 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1133 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
1138 * Handle rest request
1140 * @param handle the request handle
1143 init_cont (struct RequestHandle *handle)
1145 struct GNUNET_REST_RequestHandlerError err;
1146 static const struct GNUNET_REST_RequestHandler handlers[] = {
1147 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ALL, &ego_get_all },
1148 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_get_pubkey },
1149 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_get_name },
1150 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_get_subsystem },
1151 { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_edit_pubkey },
1152 { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_edit_name },
1153 { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_edit_subsystem },
1154 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create },
1155 { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_delete_pubkey },
1156 { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_delete_name },
1157 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont },
1158 GNUNET_REST_HANDLER_END
1162 == GNUNET_REST_handle_request (handle->rest_handle, handlers, &err,
1165 handle->response_code = err.error_code;
1166 GNUNET_SCHEDULER_add_now (&do_error, handle);
1171 * If listing is enabled, prints information about the egos.
1173 * This function is initially called for all egos and then again
1174 * whenever a ego's identifier changes or if it is deleted. At the
1175 * end of the initial pass over all egos, the function is once called
1176 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1177 * be invoked in the future or that there was an error.
1179 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1180 * this function is only called ONCE, and 'NULL' being passed in
1181 * 'ego' does indicate an error (i.e. name is taken or no default
1182 * value is known). If 'ego' is non-NULL and if '*ctx'
1183 * is set in those callbacks, the value WILL be passed to a subsequent
1184 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1185 * that one was not NULL).
1187 * When an identity is renamed, this function is called with the
1188 * (known) ego but the NEW identifier.
1190 * When an identity is deleted, this function is called with the
1191 * (known) ego and "NULL" for the 'identifier'. In this case,
1192 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1195 * @param cls closure
1196 * @param ego ego handle
1197 * @param ctx context for application to store data for this ego
1198 * (during the lifetime of this process, initially NULL)
1199 * @param identifier identifier assigned by the user for this ego,
1200 * NULL if the user just deleted the ego and it
1201 * must thus no longer be used
1204 init_egos (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx,
1205 const char *identifier)
1207 struct RequestHandle *handle = cls;
1208 struct EgoEntry *ego_entry;
1209 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1211 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1213 handle->state = ID_REST_STATE_POST_INIT;
1217 if (ID_REST_STATE_INIT == handle->state)
1219 ego_entry = GNUNET_new(struct EgoEntry);
1220 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1221 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1222 ego_entry->ego = ego;
1223 GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
1224 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail,
1230 * Function processing the REST call
1232 * @param method HTTP method
1233 * @param url URL of the HTTP request
1234 * @param data body of the HTTP request (optional)
1235 * @param data_size length of the body
1236 * @param proc callback function for the result
1237 * @param proc_cls closure for callback function
1238 * @return GNUNET_OK if request accepted
1241 rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1242 GNUNET_REST_ResultProcessor proc, void *proc_cls)
1244 struct RequestHandle *handle = GNUNET_new(struct RequestHandle);
1246 handle->response_code = 0;
1247 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1248 handle->proc_cls = proc_cls;
1249 handle->proc = proc;
1250 handle->rest_handle = rest_handle;
1251 handle->data = rest_handle->data;
1252 handle->data_size = rest_handle->data_size;
1254 handle->url = GNUNET_strdup(rest_handle->url);
1255 if (handle->url[strlen (handle->url) - 1] == '/')
1256 handle->url[strlen (handle->url) - 1] = '\0';
1257 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1259 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &init_egos, handle);
1261 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1264 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1268 * Entry point for the plugin.
1270 * @param cls Config info
1271 * @return NULL on error, otherwise the plugin context
1274 libgnunet_plugin_rest_identity_init (void *cls)
1276 static struct Plugin plugin;
1277 struct GNUNET_REST_Plugin *api;
1280 if (NULL != plugin.cfg)
1281 return NULL; /* can only initialize once! */
1282 memset (&plugin, 0, sizeof(struct Plugin));
1284 api = GNUNET_new(struct GNUNET_REST_Plugin);
1286 api->name = GNUNET_REST_API_NS_IDENTITY;
1287 api->process_request = &rest_process_request;
1288 GNUNET_asprintf (&allow_methods, "%s, %s, %s, %s, %s",
1289 MHD_HTTP_METHOD_GET,
1290 MHD_HTTP_METHOD_POST,
1291 MHD_HTTP_METHOD_PUT,
1292 MHD_HTTP_METHOD_DELETE,
1293 MHD_HTTP_METHOD_OPTIONS);
1295 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Identity REST API initialized\n"));
1300 * Exit point from the plugin.
1302 * @param cls the plugin context (as returned by "init")
1303 * @return always NULL
1306 libgnunet_plugin_rest_identity_done (void *cls)
1308 struct GNUNET_REST_Plugin *api = cls;
1309 struct Plugin *plugin = api->cls;
1312 GNUNET_free_non_null(allow_methods);
1314 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n");
1318 /* end of plugin_rest_identity.c */