From d74e6d06434f195a7307497e4e0283185491264a Mon Sep 17 00:00:00 2001 From: Phil Date: Fri, 10 Aug 2018 23:50:40 +0200 Subject: fix identity rename --- src/identity/gnunet-service-identity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/identity/gnunet-service-identity.c b/src/identity/gnunet-service-identity.c index 266f5ccc3..155c49cc5 100644 --- a/src/identity/gnunet-service-identity.c +++ b/src/identity/gnunet-service-identity.c @@ -752,7 +752,7 @@ handle_rename_message (void *cls, old_name = GNUNET_strdup (old_name_tmp); GNUNET_STRINGS_utf8_tolower (old_name_tmp, old_name); new_name = GNUNET_strdup (&old_name_tmp[old_name_len]); - GNUNET_STRINGS_utf8_tolower (&old_name_tmp[old_name_len], old_name); + GNUNET_STRINGS_utf8_tolower (&old_name_tmp[old_name_len], new_name); /* check if new name is already in use */ for (ego = ego_head; NULL != ego; ego = ego->next) -- cgit v1.2.3 From bcda92da22a3c1824f966d4593492e8a446fd070 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 11 Aug 2018 00:35:35 +0200 Subject: added additional namespaces in identity rest api --- src/identity/plugin_rest_identity.c | 614 +++++++++++++++++++----------- src/identity/test_plugin_rest_identity.sh | 99 +++-- 2 files changed, 444 insertions(+), 269 deletions(-) (limited to 'src') diff --git a/src/identity/plugin_rest_identity.c b/src/identity/plugin_rest_identity.c index a518a74cc..9a05a2054 100644 --- a/src/identity/plugin_rest_identity.c +++ b/src/identity/plugin_rest_identity.c @@ -29,22 +29,69 @@ #include "microhttpd.h" #include +/** + * Identity Namespace + */ #define GNUNET_REST_API_NS_IDENTITY "/identity" /** - * Parameter names + * Identity Namespace with public key specifier + */ +#define GNUNET_REST_API_NS_IDENTITY_ALL "/identity/all" + +/** + * Identity Namespace with public key specifier */ -#define GNUNET_REST_PARAM_PUBKEY "pubkey" -#define GNUNET_REST_PARAM_SUBSYSTEM "subsystem" -#define GNUNET_REST_PARAM_NAME "name" -#define GNUNET_REST_PARAM_NEWNAME "newname" +#define GNUNET_REST_API_NS_IDENTITY_PUBKEY "/identity/pubkey" /** - * Error messages + * Identity Namespace with public key specifier + */ +#define GNUNET_REST_API_NS_IDENTITY_NAME "/identity/name" + +/** + * Identity Subsystem Namespace + */ +#define GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM "/identity/subsystem" + +/** + * Parameter public key + */ +#define GNUNET_REST_IDENTITY_PARAM_PUBKEY "pubkey" + +/** + * Parameter subsystem + */ +#define GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM "subsystem" + +/** + * Parameter name + */ +#define GNUNET_REST_IDENTITY_PARAM_NAME "name" + +/** + * Parameter new name + */ +#define GNUNET_REST_IDENTITY_PARAM_NEWNAME "newname" + +/** + * Error message Unknown Error + */ +#define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown error" + +/** + * Error message Resource location invalid */ -#define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error" #define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid" + +/** + * Error message No data + */ #define GNUNET_REST_ERROR_NO_DATA "No data" + +/** + * Error message Data invalid + */ #define GNUNET_REST_ERROR_DATA_INVALID "Data invalid" /** @@ -106,6 +153,9 @@ struct EgoEntry struct GNUNET_IDENTITY_Ego *ego; }; +/** + * The request handle + */ struct RequestHandle { /** @@ -123,10 +173,6 @@ struct RequestHandle */ size_t data_size; - /** - * Requested Subsystem - */ - char *subsystem; /** * Ego list @@ -213,8 +259,6 @@ cleanup_handle (void *cls) handle->timeout_task = NULL; } - if (NULL != handle->subsystem) - GNUNET_free(handle->subsystem); if (NULL != handle->url) GNUNET_free(handle->url); if (NULL != handle->emsg) @@ -315,7 +359,9 @@ get_egoentry(struct RequestHandle *handle, char* pubkey, char *name) * @param name the id of the ego */ static void -ego_get_for_subsystem (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx, +ego_get_for_subsystem (void *cls, + struct GNUNET_IDENTITY_Ego *ego, + void **ctx, const char *name) { struct RequestHandle *handle = cls; @@ -337,8 +383,12 @@ ego_get_for_subsystem (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx, // create json with subsystem identity json_root = json_object (); - json_object_set_new (json_root, GNUNET_REST_PARAM_PUBKEY, json_string(public_key_string)); - json_object_set_new (json_root, GNUNET_REST_PARAM_NAME, json_string(name)); + json_object_set_new (json_root, + GNUNET_REST_IDENTITY_PARAM_PUBKEY, + json_string(public_key_string)); + json_object_set_new (json_root, + GNUNET_REST_IDENTITY_PARAM_NAME, + json_string(name)); result_str = json_dumps (json_root, 0); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); @@ -352,116 +402,75 @@ ego_get_for_subsystem (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx, } /** - * Handle identity GET request + * Handle identity GET request for subsystem * * @param con_handle the connection handle * @param url the url * @param cls the RequestHandle */ void -ego_get (struct GNUNET_REST_RequestHandle *con_handle, const char* url, - void *cls) +ego_get_subsystem (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) { struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct GNUNET_HashCode key; - struct MHD_Response *resp; - char *keystring; - char *egoname; - json_t *json_root; - json_t *json_ego; - char *result_str; + char *subsystem; - //requested default identity of subsystem - GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_SUBSYSTEM, - strlen (GNUNET_REST_PARAM_SUBSYSTEM), &key); - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains ( - handle->rest_handle->url_param_map, &key)) + if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url)) { - handle->subsystem = GNUNET_strdup( - GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, - &key)); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", - handle->subsystem); - - handle->op = GNUNET_IDENTITY_get (handle->identity_handle, - handle->subsystem, - &ego_get_for_subsystem, - handle); - if (NULL == handle->op) - { - handle->emsg = GNUNET_strdup("No identity found for subsystem"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } + handle->emsg = GNUNET_strdup("Missing subsystem"); + GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - egoname = NULL; - keystring = NULL; - - //one identity requested with key - GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_PUBKEY, - strlen (GNUNET_REST_PARAM_PUBKEY), - &key); - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains ( - handle->rest_handle->url_param_map, &key)) - { - keystring = GNUNET_CONTAINER_multihashmap_get ( - handle->rest_handle->url_param_map, &key); + subsystem = &handle->url[strlen ( + GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) + 1]; + //requested default identity of subsystem + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsystem); - ego_entry = get_egoentry(handle, keystring, NULL); - if (NULL == ego_entry) - { - handle->emsg = GNUNET_strdup("No identity found for public key"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - egoname = ego_entry->identifier; - } + handle->op = GNUNET_IDENTITY_get (handle->identity_handle, + subsystem, + &ego_get_for_subsystem, + handle); - //one identity requested with name - if (NULL == egoname) + if (NULL == handle->op) { - GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_NAME, - strlen (GNUNET_REST_PARAM_NAME), - &key); - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains ( - handle->rest_handle->url_param_map, &key)) - { - egoname = GNUNET_CONTAINER_multihashmap_get ( - handle->rest_handle->url_param_map, &key); - if (0 >= strlen(egoname)) - { - handle->emsg = GNUNET_strdup("No identity found for name"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - //LOWERCASE ego names? - GNUNET_STRINGS_utf8_tolower(egoname, egoname); - } + handle->emsg = GNUNET_strdup("No identity found for subsystem"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; } +} + + +/** + * Handle identity GET request - responds with all identities + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_get_all (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct MHD_Response *resp; + json_t *json_root; + json_t *json_ego; + char *result_str; json_root = json_array (); //Return ego/egos for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) { - //if only one ego requested - if ((NULL != egoname)){ - if(0 != strcmp (egoname, ego_entry->identifier)){ - continue; - } - } - json_ego = json_object (); json_object_set_new (json_ego, - GNUNET_REST_PARAM_PUBKEY, + GNUNET_REST_IDENTITY_PARAM_PUBKEY, json_string (ego_entry->keystring)); json_object_set_new (json_ego, - GNUNET_REST_PARAM_NAME, + GNUNET_REST_IDENTITY_PARAM_NAME, json_string (ego_entry->identifier)); json_array_append (json_root, json_ego); json_decref (json_ego); @@ -486,6 +495,113 @@ ego_get (struct GNUNET_REST_RequestHandle *con_handle, const char* url, } +/** + * Responds with the ego_entry identity + * + * @param handle the struct RequestHandle + * @param ego_entry the struct EgoEntry for the response + */ +void +ego_get_response (struct RequestHandle *handle, struct EgoEntry *ego_entry) +{ + struct MHD_Response *resp; + json_t *json_ego; + char *result_str; + + json_ego = json_object (); + json_object_set_new (json_ego, + GNUNET_REST_IDENTITY_PARAM_PUBKEY, + json_string (ego_entry->keystring)); + json_object_set_new (json_ego, + GNUNET_REST_IDENTITY_PARAM_NAME, + json_string (ego_entry->identifier)); + + result_str = json_dumps (json_ego, 0); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); + resp = GNUNET_REST_create_response (result_str); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + + json_decref (json_ego); + GNUNET_free(result_str); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + +/** + * Handle identity GET request with a public key + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *keystring; + + keystring = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) + { + handle->emsg = GNUNET_strdup("Missing public key"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1]; + ego_entry = get_egoentry(handle, keystring, NULL); + + if (NULL == ego_entry) + { + handle->emsg = GNUNET_strdup("No identity found for public key"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + ego_get_response(handle, ego_entry); +} + +/** + * Handle identity GET request with a name + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_get_name (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *egoname; + + egoname = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) + { + handle->emsg = GNUNET_strdup("Missing name"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + egoname = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1]; + ego_entry = get_egoentry(handle, NULL, egoname); + + if (NULL == ego_entry) + { + handle->emsg = GNUNET_strdup("No identity found for name"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + ego_get_response(handle, ego_entry); +} + + /** * Processing finished * @@ -505,6 +621,10 @@ do_finished (void *cls, const char *emsg) GNUNET_SCHEDULER_add_now (&do_error, handle); return; } + if (0 == handle->response_code) + { + handle->response_code = MHD_HTTP_NO_CONTENT; + } resp = GNUNET_REST_create_response (NULL); handle->proc (handle->proc_cls, resp, handle->response_code); GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); @@ -512,29 +632,22 @@ do_finished (void *cls, const char *emsg) /** - * Handle identity PUT request + * Processing edit ego with EgoEntry ego_entry * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle + * @param handle the struct RequestHandle + * @param ego_entry the struct EgoEntry we want to edit */ void -ego_edit (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) +ego_edit (struct RequestHandle *handle, struct EgoEntry *ego_entry) { - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; struct EgoEntry *ego_entry_tmp; struct MHD_Response *resp; - int json_state; json_t *data_js; json_error_t err; - char *pubkey; - char *name; char *newsubsys; char *newname; char term_data[handle->data_size + 1]; + int json_state; //if no data if (0 >= handle->data_size) @@ -555,20 +668,13 @@ ego_edit (struct GNUNET_REST_RequestHandle *con_handle, return; } - ego_entry = NULL; - pubkey = NULL; - name = NULL; newname = NULL; //NEW NAME json_state = 0; json_state = json_unpack(data_js, - "{s:s,s?:s,s?:s}", - GNUNET_REST_PARAM_NEWNAME, - &newname, - GNUNET_REST_PARAM_PUBKEY, - &pubkey, - GNUNET_REST_PARAM_NAME, - &name); + "{s:s!}", + GNUNET_REST_IDENTITY_PARAM_NEWNAME, + &newname); //Change name with pubkey or name identifier if (0 == json_state) { @@ -587,37 +693,28 @@ ego_edit (struct GNUNET_REST_RequestHandle *con_handle, json_decref (data_js); return; } - //lower case name GNUNET_STRINGS_utf8_tolower(newname,newname); - - ego_entry = get_egoentry(handle,pubkey,name); - - if (NULL == ego_entry) + ego_entry_tmp = get_egoentry(handle,NULL,newname); + if (NULL != ego_entry_tmp) { + //Ego with same name not allowed (even if its the ego we change) resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND); + handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); json_decref (data_js); return; } - - for (ego_entry_tmp = handle->ego_head; - NULL != ego_entry_tmp; ego_entry_tmp = ego_entry_tmp->next) + handle->op = GNUNET_IDENTITY_rename (handle->identity_handle, + ego_entry->identifier, + newname, + &do_finished, + handle); + if (NULL == handle->op) { - if (0 == strcasecmp (newname, ego_entry_tmp->identifier)) - { - //Ego with same name not allowed - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); - json_decref (data_js); - return; - } + handle->emsg = GNUNET_strdup("Rename was not possible"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; } - handle->response_code = MHD_HTTP_NO_CONTENT; - handle->op = GNUNET_IDENTITY_rename (handle->identity_handle, - ego_entry->identifier, newname, - &do_finished, handle); json_decref (data_js); return; } @@ -626,17 +723,13 @@ ego_edit (struct GNUNET_REST_RequestHandle *con_handle, //SUBSYSTEM json_state = 0; json_state = json_unpack(data_js, - "{s:s,s?:s,s?:s}", - GNUNET_REST_PARAM_SUBSYSTEM, - &newsubsys, - GNUNET_REST_PARAM_PUBKEY, - &pubkey, - GNUNET_REST_PARAM_NAME, - &name); + "{s:s!}", + GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM, + &newsubsys); //Change subsystem with pubkey or name identifier if (0 == json_state) { - if (NULL == newsubsys || (NULL == pubkey && NULL == name)) + if (NULL == newsubsys) { handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); GNUNET_SCHEDULER_add_now (&do_error, handle); @@ -652,22 +745,18 @@ ego_edit (struct GNUNET_REST_RequestHandle *con_handle, return; } - ego_entry = get_egoentry(handle, pubkey, name); - - if (NULL == ego_entry) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - handle->response_code = MHD_HTTP_NO_CONTENT; handle->op = GNUNET_IDENTITY_set (handle->identity_handle, newsubsys, ego_entry->ego, &do_finished, handle); + if (NULL == handle->op) + { + handle->emsg = GNUNET_strdup("Setting subsystem was not possible"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } json_decref (data_js); return; } @@ -678,6 +767,85 @@ ego_edit (struct GNUNET_REST_RequestHandle *con_handle, return; } + +/** + * Handle identity PUT request with public key + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_edit_pubkey (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *keystring; + + keystring = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup("Missing public key"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1]; + ego_entry = get_egoentry(handle, keystring, NULL); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup("No identity found for public key"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + ego_edit(handle,ego_entry); +} + +/** + * Handle identity PUT request with name + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *name; + + name = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup("Missing name"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1]; + ego_entry = get_egoentry(handle, NULL, name); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup("No identity found for name"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + ego_edit(handle,ego_entry); +} + /** * Handle identity POST request * @@ -686,7 +854,8 @@ ego_edit (struct GNUNET_REST_RequestHandle *con_handle, * @param cls the RequestHandle */ void -ego_create (struct GNUNET_REST_RequestHandle *con_handle, const char* url, +ego_create (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, void *cls) { struct RequestHandle *handle = cls; @@ -726,7 +895,7 @@ ego_create (struct GNUNET_REST_RequestHandle *con_handle, const char* url, json_unpack_state = 0; json_unpack_state = json_unpack(data_js, "{s:s!}", - GNUNET_REST_PARAM_NAME, + GNUNET_REST_IDENTITY_PARAM_NAME, &egoname); if (0 != json_unpack_state) { @@ -771,93 +940,95 @@ ego_create (struct GNUNET_REST_RequestHandle *con_handle, const char* url, } /** - * Handle identity DELETE request + * Handle identity DELETE request with public key * * @param con_handle the connection handle * @param url the url * @param cls the RequestHandle */ void -ego_delete (struct GNUNET_REST_RequestHandle *con_handle, const char* url, - void *cls) +ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) { struct RequestHandle *handle = cls; struct EgoEntry *ego_entry; - struct GNUNET_HashCode key; struct MHD_Response *resp; - const char *keystring; - char *egoname; - int ego_exists = GNUNET_NO; + char *keystring; keystring = NULL; - egoname = NULL; - //delete with pubkey - GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_PUBKEY, - strlen (GNUNET_REST_PARAM_PUBKEY), &key); - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains ( - handle->rest_handle->url_param_map, &key)) + if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) { - keystring = GNUNET_CONTAINER_multihashmap_get ( - handle->rest_handle->url_param_map,&key); + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup("Missing public key"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; } + keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1]; + ego_entry = get_egoentry(handle, keystring, NULL); - GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_NAME, - strlen (GNUNET_REST_PARAM_NAME), &key); - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains ( - handle->rest_handle->url_param_map, &key)) + if (NULL == ego_entry) { - egoname = GNUNET_CONTAINER_multihashmap_get ( - handle->rest_handle->url_param_map, &key); - //LOWERCASE ego names? - //GNUNET_STRINGS_utf8_tolower(egoname, egoname); + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); + return; } - if (NULL != keystring) - { - for (ego_entry = handle->ego_head; - NULL != ego_entry; ego_entry = ego_entry->next) - { - if (0 != strcasecmp (keystring, ego_entry->keystring)) - continue; - ego_exists = GNUNET_YES; - break; - } - } - else if (NULL != egoname) - { - for (ego_entry = handle->ego_head; - NULL != ego_entry; ego_entry = ego_entry->next) - { - if (0 != strcmp (egoname, ego_entry->identifier)) - continue; - ego_exists = GNUNET_YES; - break; - } - } - else + handle->response_code = MHD_HTTP_NO_CONTENT; + handle->op = GNUNET_IDENTITY_delete (handle->identity_handle, + ego_entry->identifier, + &do_finished, + handle); +} + + +/** + * Handle identity DELETE request with name + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct MHD_Response *resp; + char *name; + + name = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) { - handle->emsg = GNUNET_strdup("Missing parameter pubkey or name"); + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup("Missing public key"); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } + name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1]; + ego_entry = get_egoentry(handle, NULL, name); - if (GNUNET_NO == ego_exists) + if (NULL == ego_entry) { resp = GNUNET_REST_create_response (NULL); handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND); GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); return; } + handle->response_code = MHD_HTTP_NO_CONTENT; handle->op = GNUNET_IDENTITY_delete (handle->identity_handle, - ego_entry->identifier, &do_finished, + ego_entry->identifier, + &do_finished, handle); - } + /** * Respond to OPTIONS request * @@ -890,10 +1061,15 @@ init_cont (struct RequestHandle *handle) { struct GNUNET_REST_RequestHandlerError err; static const struct GNUNET_REST_RequestHandler handlers[] = { - { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_get }, - { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY, &ego_edit }, + { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ALL, &ego_get_all }, + { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_get_pubkey }, + { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_get_name }, + { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_get_subsystem }, + { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_edit_pubkey }, + { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_edit_name }, { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create }, - { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY, &ego_delete }, + { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_delete_pubkey }, + { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_delete_name }, { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont }, GNUNET_REST_HANDLER_END }; diff --git a/src/identity/test_plugin_rest_identity.sh b/src/identity/test_plugin_rest_identity.sh index d9377500e..3eac0950c 100755 --- a/src/identity/test_plugin_rest_identity.sh +++ b/src/identity/test_plugin_rest_identity.sh @@ -58,31 +58,31 @@ test="$(gnunet-identity -d)" #if no identity exists if [ "" == "$test" ] then - curl_get "$identity_link" "error" + curl_get "$identity_link/all" "error" gnunet-identity -C "test_plugin_rest_identity" name="$(gnunet-identity -d | awk 'NR==1{print $1}')" public="$(gnunet-identity -d | awk 'NR==1{print $3}')" - curl_get "${identity_link}?name=$name" "$public" - curl_get "${identity_link}?name=" "error" - curl_get "${identity_link}?name=$public" "error" + curl_get "${identity_link}/name/$name" "$public" + curl_get "${identity_link}/name/$public" "error" + curl_get "${identity_link}/name/" "error" - curl_get "${identity_link}?pubkey=$public" "$name" - curl_get "${identity_link}?pubkey=$name" "error" - curl_get "${identity_link}?pubkey=" "error" + curl_get "${identity_link}/pubkey/$public" "$name" + curl_get "${identity_link}/pubkey/$name" "error" + curl_get "${identity_link}/pubkey/" "error" gnunet-identity -D "test_plugin_rest_identity" else name="$(gnunet-identity -d | awk 'NR==1{print $1}')" public="$(gnunet-identity -d | awk 'NR==1{print $3}')" - curl_get "${identity_link}?name=$name" "$public" - curl_get "${identity_link}?name=" "error" - curl_get "${identity_link}?name=$public" "error" + curl_get "${identity_link}/name/$name" "$public" + curl_get "${identity_link}/name/$public" "error" + curl_get "${identity_link}/name/" "error" - curl_get "${identity_link}?pubkey=$public" "$name" - curl_get "${identity_link}?pubkey=$name" "error" - curl_get "${identity_link}?pubkey=" "error" + curl_get "${identity_link}/pubkey/$public" "$name" + curl_get "${identity_link}/pubkey/$name" "error" + curl_get "${identity_link}/pubkey/" "error" fi #Test POST @@ -105,55 +105,54 @@ curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1", "other":"tes name="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $1}')" public="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $3}')" -curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":"'$public'"}' "HTTP/1.1 204" -curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":"'$public'"}' "HTTP/1.1 409" -curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":"'$public'xx"}' "HTTP/1.1 404" -curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":""}' "HTTP/1.1 404" -curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubke":""}' "HTTP/1.1 404" -curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubke":"","other":"sdfdsf"}' "HTTP/1.1 404" -curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubke":"","name":"sdfdsf"}' "HTTP/1.1 404" -curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity","pubke":"","name":"test_plugin_rest_identity1"}' "HTTP/1.1 204" -curl_put "${identity_link}" '{"newnam":"test_plugin_rest_identity","pubkey":"'$public'"}' "error" -curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","name":"test_plugin_rest_identity"}' "HTTP/1.1 204" -curl_put "${identity_link}" '{"newname":"TEST_plugin_rest_identity1","name":"test_plugin_rest_identity1"}' "HTTP/1.1 409" -curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","name":"test_plugin_rest_identity1"}' "HTTP/1.1 409" -curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity","name":"test_plugin_rest_identityxxx"}' "HTTP/1.1 404" -curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity","name":"test_plugin_rest_identity1"}' "HTTP/1.1 204" -curl_put "${identity_link}" '{"newnam":"test_plugin_rest_identityfail","name":"test_plugin_rest_identity"}' "error" - +curl_put "${identity_link}/pubkey/$public" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 204" +curl_put "${identity_link}/pubkey/$public" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 409" +curl_put "${identity_link}/pubkey/${public}xx" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404" +curl_put "${identity_link}/pubkey/" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404" +curl_put "${identity_link}/pubke" '{"newname":"test_plugin_rest_identity1"}' "error" +curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","other":"sdfdsf"}' "error" +curl_put "${identity_link}/pubkey/$name" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404" +curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"test_plugin_rest_identity"}' "HTTP/1.1 204" +curl_put "${identity_link}/pubkey/$public" '{"newnam":"test_plugin_rest_identity"}' "error" +curl_put "${identity_link}/name/test_plugin_rest_identity" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 204" +curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"TEST_plugin_rest_identity1"}' "HTTP/1.1 409" +curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 409" +curl_put "${identity_link}/name/test_plugin_rest_identityxxx" '{"newname":"test_plugin_rest_identity"}' "HTTP/1.1 404" +curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"test_plugin_rest_identity"}' "HTTP/1.1 204" +curl_put "${identity_link}/name/test_plugin_rest_identity" '{"newnam":"test_plugin_rest_identityfail"}' "error" #Test subsystem -curl_put "${identity_link}" '{"subsystem":"namestore","name":"test_plugin_rest_identity"}' "HTTP/1.1 204" -curl_put "${identity_link}" '{"subsystem":"namestore","name":"test_plugin_rest_identity"}' "HTTP/1.1 204" -curl_get "${identity_link}?subsystem=namestore" "test_plugin_rest_identity" +curl_put "${identity_link}/name/test_plugin_rest_identity" '{"subsystem":"namestore"}' "HTTP/1.1 204" +curl_put "${identity_link}/name/test_plugin_rest_identity" '{"subsystem":"namestore"}' "HTTP/1.1 204" +curl_get "${identity_link}/subsystem/namestore" "test_plugin_rest_identity" curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created" public="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $3}')" -curl_put "${identity_link}" '{"subsystem":"namestore","pubkey":"'"$public"'"}' "HTTP/1.1 204" -curl_get "${identity_link}?subsystem=namestore" "test_plugin_rest_identity1" -curl_get "${identity_link}?subsystem=test_plugin_rest_identity_no_subsystem" "error" -curl_put "${identity_link}" '{"subsystem":"test_plugin_rest_identity_no_subsystem","name":"test_plugin_rest_identity1"}' "HTTP/1.1 204" -curl_get "${identity_link}?subsystem=test_plugin_rest_identity_no_subsystem" "test_plugin_rest_identity1" +curl_put "${identity_link}/pubkey/$public" '{"subsystem":"namestore"}' "HTTP/1.1 204" +curl_get "${identity_link}/subsystem/namestore" "test_plugin_rest_identity1" +curl_get "${identity_link}/subsystem/test_plugin_rest_identity_no_subsystem" "error" +curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"subsystem":"test_plugin_rest_identity_no_subsystem"}' "HTTP/1.1 204" +curl_get "${identity_link}/subsystem/test_plugin_rest_identity_no_subsystem" "test_plugin_rest_identity1" -curl_put "${identity_link}" '{"subsyste":"test_plugin_rest_identity_no_subsystem","name":"test_plugin_rest_identity1"}' "error" -curl_put "${identity_link}" '{"subsystem":"test_plugin_rest_identity_no_subsystem","name":"Test_plugin_rest_identity1"}' "HTTP/1.1 204" +curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"subsyste":"test_plugin_rest_identity_no_subsystem"}' "error" +curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"subsystem":"test_plugin_rest_identity_no_subsystem"}' "HTTP/1.1 204" #Test DELETE -curl_delete "${identity_link}?name=test_plugin_rest_identity" "HTTP/1.1 204" -curl_get "${identity_link}?name=test_plugin_rest_identity" "error" -curl_delete "${identity_link}?name=TEST_plugin_rest_identity1" "HTTP/1.1 404" -curl_delete "${identity_link}?name=test_plugin_rest_identity1" "HTTP/1.1 204" -curl_get "${identity_link}?name=test_plugin_rest_identity1" "error" -curl_delete "${identity_link}?name=test_plugin_rest_identity_not_found" "HTTP/1.1 404" +curl_delete "${identity_link}/name/test_plugin_rest_identity" "HTTP/1.1 204" +curl_get "${identity_link}/name/test_plugin_rest_identity" "error" +curl_delete "${identity_link}/name/TEST_plugin_rest_identity1" "HTTP/1.1 204" +curl_delete "${identity_link}/name/test_plugin_rest_identity1" "HTTP/1.1 404" +curl_get "${identity_link}/name/test_plugin_rest_identity1" "error" +curl_delete "${identity_link}/name/test_plugin_rest_identity_not_found" "HTTP/1.1 404" curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created" public="$(gnunet-identity -d | grep "test_plugin_rest_identity1" | awk 'NR==1{print $3}')" -curl_delete "${identity_link}?pubkey=$public" "HTTP/1.1 204" -curl_delete "${identity_link}?pubke=$public" "error" -curl_delete "${identity_link}?pubkey=$public&other=232" "HTTP/1.1 404" +curl_delete "${identity_link}/pubkey/$public" "HTTP/1.1 204" +curl_delete "${identity_link}/pubke/$public" "error" +curl_delete "${identity_link}/pubkey/${public}other=232" "HTTP/1.1 404" #Test wrong_link curl_get "$wrong_link" "HTTP/1.1 404" curl_post "$wrong_link" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 404" -curl_put "$wrong_link" '{"newname":"test_plugin_rest_identity1","name":"test_plugin_rest_identity"}' "HTTP/1.1 404" -curl_delete "$wrong_link?name=test_plugin_rest_identity1" "HTTP/1.1 404" +curl_put "$wrong_link/name/test_plugin_rest_identity" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404" +curl_delete "$wrong_link/name/test_plugin_rest_identity1" "HTTP/1.1 404" exit 0; -- cgit v1.2.3 From 4898de50936164f8adb067c4f32fab62bec92e19 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 11 Aug 2018 14:21:58 +0200 Subject: split namespace of put request in identity rest api --- src/identity/plugin_rest_identity.c | 278 +++++++++++++++++++----------- src/identity/test_plugin_rest_identity.sh | 15 +- 2 files changed, 188 insertions(+), 105 deletions(-) (limited to 'src') diff --git a/src/identity/plugin_rest_identity.c b/src/identity/plugin_rest_identity.c index 9a05a2054..89f6e7f8b 100644 --- a/src/identity/plugin_rest_identity.c +++ b/src/identity/plugin_rest_identity.c @@ -77,12 +77,22 @@ /** * Error message Unknown Error */ -#define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown error" +#define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error" /** - * Error message Resource location invalid + * Error message No identity found */ -#define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid" +#define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found" + +/** + * Error message Missing identity name + */ +#define GNUNET_REST_IDENTITY_MISSING_NAME "Missing identity name" + +/** + * Error message Missing identity name + */ +#define GNUNET_REST_IDENTITY_MISSING_PUBKEY "Missing identity public key" /** * Error message No data @@ -235,7 +245,7 @@ struct RequestHandle char *emsg; /** - * Reponse code + * Response code */ int response_code; @@ -373,7 +383,8 @@ ego_get_for_subsystem (void *cls, if(NULL == ego) { - handle->emsg = GNUNET_strdup("No identity found for subsystem"); + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -418,7 +429,7 @@ ego_get_subsystem (struct GNUNET_REST_RequestHandle *con_handle, if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url)) { - handle->emsg = GNUNET_strdup("Missing subsystem"); + handle->emsg = GNUNET_strdup("Missing subsystem name"); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -434,7 +445,8 @@ ego_get_subsystem (struct GNUNET_REST_RequestHandle *con_handle, if (NULL == handle->op) { - handle->emsg = GNUNET_strdup("No identity found for subsystem"); + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -479,7 +491,8 @@ ego_get_all (struct GNUNET_REST_RequestHandle *con_handle, if ((size_t) 0 == json_array_size (json_root)) { json_decref (json_root); - handle->emsg = GNUNET_strdup("No identities found!"); + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -547,7 +560,7 @@ ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle, if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) { - handle->emsg = GNUNET_strdup("Missing public key"); + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -556,7 +569,8 @@ ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle, if (NULL == ego_entry) { - handle->emsg = GNUNET_strdup("No identity found for public key"); + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -584,7 +598,7 @@ ego_get_name (struct GNUNET_REST_RequestHandle *con_handle, if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) { - handle->emsg = GNUNET_strdup("Missing name"); + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -593,7 +607,8 @@ ego_get_name (struct GNUNET_REST_RequestHandle *con_handle, if (NULL == ego_entry) { - handle->emsg = GNUNET_strdup("No identity found for name"); + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -644,7 +659,6 @@ ego_edit (struct RequestHandle *handle, struct EgoEntry *ego_entry) struct MHD_Response *resp; json_t *data_js; json_error_t err; - char *newsubsys; char *newname; char term_data[handle->data_size + 1]; int json_state; @@ -676,95 +690,56 @@ ego_edit (struct RequestHandle *handle, struct EgoEntry *ego_entry) GNUNET_REST_IDENTITY_PARAM_NEWNAME, &newname); //Change name with pubkey or name identifier - if (0 == json_state) + if (0 != json_state) { - if (NULL == newname) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - if (0 >= strlen(newname)) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - GNUNET_STRINGS_utf8_tolower(newname,newname); - ego_entry_tmp = get_egoentry(handle,NULL,newname); - if (NULL != ego_entry_tmp) - { - //Ego with same name not allowed (even if its the ego we change) - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); - json_decref (data_js); - return; - } - handle->op = GNUNET_IDENTITY_rename (handle->identity_handle, - ego_entry->identifier, - newname, - &do_finished, - handle); - if (NULL == handle->op) - { - handle->emsg = GNUNET_strdup("Rename was not possible"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); json_decref (data_js); return; } - newsubsys = NULL; - //SUBSYSTEM - json_state = 0; - json_state = json_unpack(data_js, - "{s:s!}", - GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM, - &newsubsys); - //Change subsystem with pubkey or name identifier - if (0 == json_state) + if (NULL == newname) { - if (NULL == newsubsys) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - if (0 >= strlen(newsubsys)) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } - handle->response_code = MHD_HTTP_NO_CONTENT; - handle->op = GNUNET_IDENTITY_set (handle->identity_handle, - newsubsys, - ego_entry->ego, - &do_finished, - handle); - if (NULL == handle->op) - { - handle->emsg = GNUNET_strdup("Setting subsystem was not possible"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } + if (0 >= strlen (newname)) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); json_decref (data_js); return; } - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); + ego_entry_tmp = get_egoentry (handle, NULL, newname); + if (NULL != ego_entry_tmp) + { + //Ego with same name not allowed (even if its the ego we change) + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); + json_decref (data_js); + return; + } + handle->op = GNUNET_IDENTITY_rename (handle->identity_handle, + ego_entry->identifier, + newname, + &do_finished, + handle); + if (NULL == handle->op) + { + handle->emsg = GNUNET_strdup("Rename failed"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } json_decref (data_js); return; + } @@ -789,7 +764,7 @@ ego_edit_pubkey (struct GNUNET_REST_RequestHandle *con_handle, if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) { handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup("Missing public key"); + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -799,7 +774,7 @@ ego_edit_pubkey (struct GNUNET_REST_RequestHandle *con_handle, if (NULL == ego_entry) { handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup("No identity found for public key"); + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -828,7 +803,7 @@ ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle, if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) { handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup("Missing name"); + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -838,7 +813,7 @@ ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle, if (NULL == ego_entry) { handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup("No identity found for name"); + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -846,6 +821,115 @@ ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle, ego_edit(handle,ego_entry); } +/** + * Handle identity subsystem PUT request with name + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_edit_subsystem (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + json_t *data_js; + json_error_t err; + char *newsubsys; + char *name; + char term_data[handle->data_size + 1]; + int json_state; + + name = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM)+1]; + ego_entry = get_egoentry(handle, NULL, name); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + //if no data + if (0 >= handle->data_size) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + //if not json + term_data[handle->data_size] = '\0'; + GNUNET_memcpy(term_data, handle->data, handle->data_size); + data_js = json_loads (term_data,JSON_DECODE_ANY,&err); + + if (NULL == data_js) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + newsubsys = NULL; + //SUBSYSTEM + json_state = 0; + json_state = json_unpack(data_js, + "{s:s!}", + GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM, + &newsubsys); + //Change subsystem with pubkey or name identifier + if (0 != json_state) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + if (NULL == newsubsys) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + if (0 >= strlen (newsubsys)) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + handle->response_code = MHD_HTTP_NO_CONTENT; + handle->op = GNUNET_IDENTITY_set (handle->identity_handle, + newsubsys, + ego_entry->ego, + &do_finished, + handle); + if (NULL == handle->op) + { + handle->emsg = GNUNET_strdup("Setting subsystem failed"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + json_decref (data_js); + return; + +} + /** * Handle identity POST request * @@ -869,7 +953,6 @@ ego_create (struct GNUNET_REST_RequestHandle *con_handle, if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url)) { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_RESOURCE_INVALID); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -907,7 +990,7 @@ ego_create (struct GNUNET_REST_RequestHandle *con_handle, if (NULL == egoname) { - handle->emsg = GNUNET_strdup("No name provided"); + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); GNUNET_SCHEDULER_add_now (&do_error, handle); json_decref (data_js); return; @@ -915,7 +998,7 @@ ego_create (struct GNUNET_REST_RequestHandle *con_handle, if (0 >= strlen (egoname)) { json_decref (data_js); - handle->emsg = GNUNET_strdup("No name provided"); + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -961,7 +1044,7 @@ ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle, if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) { handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup("Missing public key"); + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -1006,7 +1089,7 @@ ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle, if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) { handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup("Missing public key"); + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -1067,6 +1150,7 @@ init_cont (struct RequestHandle *handle) { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_get_subsystem }, { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_edit_pubkey }, { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_edit_name }, + { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_edit_subsystem }, { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create }, { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_delete_pubkey }, { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_delete_name }, diff --git a/src/identity/test_plugin_rest_identity.sh b/src/identity/test_plugin_rest_identity.sh index 3eac0950c..a5879dd7e 100755 --- a/src/identity/test_plugin_rest_identity.sh +++ b/src/identity/test_plugin_rest_identity.sh @@ -122,19 +122,18 @@ curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"test_pl curl_put "${identity_link}/name/test_plugin_rest_identity" '{"newnam":"test_plugin_rest_identityfail"}' "error" #Test subsystem -curl_put "${identity_link}/name/test_plugin_rest_identity" '{"subsystem":"namestore"}' "HTTP/1.1 204" -curl_put "${identity_link}/name/test_plugin_rest_identity" '{"subsystem":"namestore"}' "HTTP/1.1 204" +curl_put "${identity_link}/subsystem/test_plugin_rest_identity" '{"subsystem":"namestore"}' "HTTP/1.1 204" +curl_put "${identity_link}/subsystem/test_plugin_rest_identity" '{"subsystem":"namestore"}' "HTTP/1.1 204" curl_get "${identity_link}/subsystem/namestore" "test_plugin_rest_identity" -curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created" public="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $3}')" -curl_put "${identity_link}/pubkey/$public" '{"subsystem":"namestore"}' "HTTP/1.1 204" -curl_get "${identity_link}/subsystem/namestore" "test_plugin_rest_identity1" +curl_put "${identity_link}/subsystem/$public" '{"subsystem":"namestore"}' "HTTP/1.1 404" +curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created" curl_get "${identity_link}/subsystem/test_plugin_rest_identity_no_subsystem" "error" -curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"subsystem":"test_plugin_rest_identity_no_subsystem"}' "HTTP/1.1 204" +curl_put "${identity_link}/subsystem/test_plugin_rest_identity1" '{"subsystem":"test_plugin_rest_identity_no_subsystem"}' "HTTP/1.1 204" curl_get "${identity_link}/subsystem/test_plugin_rest_identity_no_subsystem" "test_plugin_rest_identity1" -curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"subsyste":"test_plugin_rest_identity_no_subsystem"}' "error" -curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"subsystem":"test_plugin_rest_identity_no_subsystem"}' "HTTP/1.1 204" +curl_put "${identity_link}/subsystem/test_plugin_rest_identity1" '{"subsyste":"test_plugin_rest_identity_no_subsystem"}' "error" +curl_put "${identity_link}/subsystem/test_plugin_rest_identity1" '{"subsystem":"test_plugin_rest_identity_no_subsystem"}' "HTTP/1.1 204" #Test DELETE curl_delete "${identity_link}/name/test_plugin_rest_identity" "HTTP/1.1 204" -- cgit v1.2.3 From 89485145a0f33984a70bffdf0f766667b4a3e75e Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 12 Aug 2018 01:46:11 +0200 Subject: rewrite error handling and subsystem PUT --- src/identity/plugin_rest_identity.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/identity/plugin_rest_identity.c b/src/identity/plugin_rest_identity.c index 89f6e7f8b..9f1765a63 100644 --- a/src/identity/plugin_rest_identity.c +++ b/src/identity/plugin_rest_identity.c @@ -560,6 +560,7 @@ ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle, if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) { + handle->response_code = MHD_HTTP_NOT_FOUND; handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); GNUNET_SCHEDULER_add_now (&do_error, handle); return; @@ -598,6 +599,7 @@ ego_get_name (struct GNUNET_REST_RequestHandle *con_handle, if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) { + handle->response_code = MHD_HTTP_NOT_FOUND; handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); GNUNET_SCHEDULER_add_now (&do_error, handle); return; @@ -1036,7 +1038,6 @@ ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle, { struct RequestHandle *handle = cls; struct EgoEntry *ego_entry; - struct MHD_Response *resp; char *keystring; keystring = NULL; @@ -1053,9 +1054,9 @@ ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle, if (NULL == ego_entry) { - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -1081,7 +1082,6 @@ ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle, { struct RequestHandle *handle = cls; struct EgoEntry *ego_entry; - struct MHD_Response *resp; char *name; name = NULL; @@ -1098,9 +1098,9 @@ ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle, if (NULL == ego_entry) { - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); return; } -- cgit v1.2.3 From 4df7069dcd17ac39c786ee6f21455c96e6a6dbf4 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 12 Aug 2018 23:11:10 +0200 Subject: Changed Namestore API, changed error handling, changed gns record json --- src/gns/plugin_rest_gns.c | 62 +++-- src/gns/test_plugin_rest_gns.sh | 22 +- src/json/json_generator.c | 32 ++- src/json/json_gnsrecord.c | 8 +- src/namestore/plugin_rest_namestore.c | 407 ++++++++++++---------------- src/namestore/test_plugin_rest_namestore.sh | 137 +++------- src/peerinfo/plugin_rest_peerinfo.c | 55 ++-- 7 files changed, 329 insertions(+), 394 deletions(-) (limited to 'src') diff --git a/src/gns/plugin_rest_gns.c b/src/gns/plugin_rest_gns.c index fd2469577..0bf4198fc 100644 --- a/src/gns/plugin_rest_gns.c +++ b/src/gns/plugin_rest_gns.c @@ -30,14 +30,26 @@ #include "microhttpd.h" #include +/** + * Rest API GNS Namespace + */ #define GNUNET_REST_API_NS_GNS "/gns" - -#define GNUNET_REST_GNS_PARAM_NAME "name" - +/** + * Rest API GNS Parameter record_type + */ #define GNUNET_REST_GNS_PARAM_RECORD_TYPE "record_type" + +/** + * Rest API GNS ERROR Unknown Error + */ #define GNUNET_REST_GNS_ERROR_UNKNOWN "Unknown Error" +/** + * Rest API GNS ERROR Record not found + */ +#define GNUNET_REST_GNS_NOT_FOUND "Record not found" + /** * The configuration handle */ @@ -56,7 +68,9 @@ struct Plugin const struct GNUNET_CONFIGURATION_Handle *cfg; }; - +/** + * The request handle + */ struct RequestHandle { @@ -116,7 +130,7 @@ struct RequestHandle char *emsg; /** - * Reponse code + * Response code */ int response_code; @@ -214,7 +228,8 @@ handle_gns_response (void *cls, if (GNUNET_NO == was_gns) { - handle->emsg = GNUNET_strdup("Name not found in GNS"); + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_GNS_NOT_FOUND); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -260,21 +275,24 @@ get_gns_cont (struct GNUNET_REST_RequestHandle *con_handle, char *record_type; char *name; - GNUNET_CRYPTO_hash (GNUNET_REST_GNS_PARAM_NAME, - strlen (GNUNET_REST_GNS_PARAM_NAME), - &key); - if ( GNUNET_NO - == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, - &key)) + name = NULL; + handle->name = NULL; + if (strlen (GNUNET_REST_API_NS_GNS) < strlen (handle->url)) + { + name = &handle->url[strlen (GNUNET_REST_API_NS_GNS) + 1]; + } + + if (NULL == name) { - handle->emsg = GNUNET_strdup("Parameter name is missing"); + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_GNS_NOT_FOUND); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - name = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,&key); - if(0 >= strlen (name)) + if (0 >= strlen (name)) { - handle->emsg = GNUNET_strdup("Length of parameter name is zero"); + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_GNS_NOT_FOUND); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -292,27 +310,17 @@ get_gns_cont (struct GNUNET_REST_RequestHandle *con_handle, handle->record_type = GNUNET_GNSRECORD_typename_to_number(record_type); } - if(UINT32_MAX == handle->record_type) { handle->record_type = GNUNET_GNSRECORD_TYPE_ANY; } - handle->gns = GNUNET_GNS_connect (cfg); - if (NULL == handle->gns) - { - handle->emsg = GNUNET_strdup ("GNS not available"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->gns_lookup = GNUNET_GNS_lookup_with_tld (handle->gns, handle->name, handle->record_type, GNUNET_NO, &handle_gns_response, handle); - return; } @@ -397,7 +405,7 @@ rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle, if (handle->url[strlen (handle->url)-1] == '/') handle->url[strlen (handle->url)-1] = '\0'; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); - + handle->gns = GNUNET_GNS_connect (cfg); init_cont(handle); handle->timeout_task = diff --git a/src/gns/test_plugin_rest_gns.sh b/src/gns/test_plugin_rest_gns.sh index 7ede44501..ec495a04b 100755 --- a/src/gns/test_plugin_rest_gns.sh +++ b/src/gns/test_plugin_rest_gns.sh @@ -19,32 +19,32 @@ curl_get () { gnunet-identity -D "test_plugin_rest_gns" > /dev/null 2>&1 -curl_get "$gns_link?name=www.test_plugin_rest_gns" "error" +curl_get "$gns_link/www.test_plugin_rest_gns" "error" gnunet-identity -C "test_plugin_rest_gns" -curl_get "$gns_link?name=www.test_plugin_rest_gns" "\[\]" +curl_get "$gns_link/www.test_plugin_rest_gns" "\[\]" gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1.1.1.1 -t A -curl_get "$gns_link?name=www.test_plugin_rest_gns" "1.1.1.1" +curl_get "$gns_link/www.test_plugin_rest_gns" "1.1.1.1" gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1::1 -t AAAA -curl_get "$gns_link?name=www.test_plugin_rest_gns" "1::1.*1.1.1.1" +curl_get "$gns_link/www.test_plugin_rest_gns" "1::1.*1.1.1.1" gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1.1.1.2 -t A -curl_get "$gns_link?name=www.test_plugin_rest_gns" "1.1.1.2.*1::1.*1.1.1.1" -curl_get "$gns_link?name=www.test_plugin_rest_gns&record_type=A" "1.1.1.2.*1.1.1.1" -curl_get "$gns_link?name=www.test_plugin_rest_gns&record_type=AAAA" "1::1" -curl_get "$gns_link?name=www.test_plugin_rest_gns&record_type=WRONG_TYPE" "1.1.1.2.*1::1.*1.1.1.1" +curl_get "$gns_link/www.test_plugin_rest_gns" "1.1.1.2.*1::1.*1.1.1.1" +curl_get "$gns_link/www.test_plugin_rest_gns?record_type=A" "1.1.1.2.*1.1.1.1" +curl_get "$gns_link/www.test_plugin_rest_gns?record_type=AAAA" "1::1" +curl_get "$gns_link/www.test_plugin_rest_gns?record_type=WRONG_TYPE" "1.1.1.2.*1::1.*1.1.1.1" gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www1 -e 1d -V 1.1.1.1 -t A -curl_get "$gns_link?name=www1.test_plugin_rest_gns" "1.1.1.1" +curl_get "$gns_link/www1.test_plugin_rest_gns" "1.1.1.1" -gnunet-identity -D "test_plugin_rest_gns" +gnunet-identity -D "test_plugin_rest_gns" > /dev/null 2>&1 -curl_get "$gns_link?name=www1.test_plugin_rest_gns" "error" +curl_get "$gns_link/www1.test_plugin_rest_gns" "error" exit 0 diff --git a/src/json/json_generator.c b/src/json/json_generator.c index d8c82bc86..0ffe5c643 100644 --- a/src/json/json_generator.c +++ b/src/json/json_generator.c @@ -182,12 +182,32 @@ GNUNET_JSON_from_gns_record (const char* rname, record_type_str = GNUNET_GNSRECORD_number_to_typename(rd->record_type); // ? for possible NULL values - ret = json_pack("{s:s?,s:s?,s:s?,s:i,s:s?}", - "value", value_str, - "type", record_type_str, - "expiration_time", expiration_time_str, - "flag", flags, - "label", rname); + if (NULL != rname) + { + ret = json_pack ("{s:s?,s:s?,s:s?,s:i,s:s?}", + "value", + value_str, + "record_type", + record_type_str, + "expiration_time", + expiration_time_str, + "flag", + flags, + "label", + rname); + } + else + { + ret = json_pack ("{s:s?,s:s?,s:s?,s:i}", + "value", + value_str, + "record_type", + record_type_str, + "expiration_time", + expiration_time_str, + "flag", + flags); + } GNUNET_free_non_null(value_str); return ret; } diff --git a/src/json/json_gnsrecord.c b/src/json/json_gnsrecord.c index 7bdf97f06..fe51119b1 100644 --- a/src/json/json_gnsrecord.c +++ b/src/json/json_gnsrecord.c @@ -26,10 +26,10 @@ #include "gnunet_json_lib.h" #define GNUNET_JSON_GNSRECORD_VALUE "value" -#define GNUNET_JSON_GNSRECORD_TYPE "type" +#define GNUNET_JSON_GNSRECORD_TYPE "record_type" #define GNUNET_JSON_GNSRECORD_EXPIRATION_TIME "expiration_time" #define GNUNET_JSON_GNSRECORD_FLAG "flag" -#define GNUNET_JSON_GNSRECORD_LABEL "label" +#define GNUNET_JSON_GNSRECORD_RECORD_NAME "record_name" #define GNUNET_JSON_GNSRECORD_NEVER "never" @@ -52,7 +52,7 @@ parse_gnsrecordobject (void *cls, const char *value; const char *expiration_time; const char *record_type; - const char *label; + const char *name; int flag; void *rdata = NULL; size_t rdata_size; @@ -71,7 +71,7 @@ parse_gnsrecordobject (void *cls, GNUNET_JSON_GNSRECORD_TYPE, &record_type, GNUNET_JSON_GNSRECORD_EXPIRATION_TIME, &expiration_time, GNUNET_JSON_GNSRECORD_FLAG, &flag, - GNUNET_JSON_GNSRECORD_LABEL, &label); + GNUNET_JSON_GNSRECORD_RECORD_NAME, &name); if (0 != unpack_state) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, diff --git a/src/namestore/plugin_rest_namestore.c b/src/namestore/plugin_rest_namestore.c index f14707cce..1d72d13ff 100644 --- a/src/namestore/plugin_rest_namestore.c +++ b/src/namestore/plugin_rest_namestore.c @@ -32,22 +32,40 @@ #include "microhttpd.h" #include - +/** + * Namestore Namespace + */ #define GNUNET_REST_API_NS_NAMESTORE "/namestore" -#define GNUNET_REST_SUBSYSTEM_NAMESTORE "namestore" /** - * Parameter names + * Error message Unknown Error */ -#define GNUNET_REST_API_PARAM_PUBKEY "pubkey" -#define GNUNET_REST_API_PARAM_NAME "name" +#define GNUNET_REST_NAMESTORE_ERROR_UNKNOWN "Unknown Error" /** - * Error messages + * Error message No identity found */ -#define GNUNET_REST_NAMESTORE_ERROR_UNKNOWN "Unknown Error" +#define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found" -#define GNUNET_REST_NAMESTORE_RD_COUNT 1 +/** + * Error message No default zone specified + */ +#define GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE "No default zone specified" + +/** + * Error message Failed request + */ +#define GNUNET_REST_NAMESTORE_FAILED "Namestore action failed" + +/** + * Error message invalid data + */ +#define GNUNET_REST_NAMESTORE_INVALID_DATA "Data invalid" + +/** + * Error message No data + */ +#define GNUNET_REST_NAMESTORE_NO_DATA "No data" /** * State while collecting all egos @@ -107,13 +125,15 @@ struct EgoEntry struct GNUNET_IDENTITY_Ego *ego; }; - +/** + * The request handle + */ struct RequestHandle { /** * Records to store */ - char *label_name; + char *record_name; /** * Records to store @@ -211,7 +231,7 @@ struct RequestHandle char *emsg; /** - * Reponse code + * Response code */ int response_code; @@ -235,8 +255,8 @@ cleanup_handle (void *cls) GNUNET_SCHEDULER_cancel (handle->timeout_task); handle->timeout_task = NULL; } - if (NULL != handle->label_name) - GNUNET_free(handle->label_name); + if (NULL != handle->record_name) + GNUNET_free(handle->record_name); if (NULL != handle->url) GNUNET_free(handle->url); if (NULL != handle->emsg) @@ -318,20 +338,9 @@ do_error (void *cls) * @return EgoEntry or NULL if not found */ struct EgoEntry* -get_egoentry(struct RequestHandle *handle, char* pubkey, char *name) +get_egoentry_namestore(struct RequestHandle *handle, char *name) { struct EgoEntry *ego_entry; - if (NULL != pubkey) - { - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (0 != strcasecmp (pubkey, ego_entry->keystring)) - continue; - return ego_entry; - } - } if (NULL != name) { for (ego_entry = handle->ego_head; @@ -349,17 +358,26 @@ get_egoentry(struct RequestHandle *handle, char* pubkey, char *name) /** * Does internal server error when iteration failed. + * + * @param cls the `struct RequestHandle` */ static void namestore_iteration_error (void *cls) { struct RequestHandle *handle = cls; - struct MHD_Response *resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_INTERNAL_SERVER_ERROR); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; } +/** + * Create finished callback + * + * @param cls the `struct RequestHandle` + * @param success the success indicating integer, GNUNET_OK on success + * @param emsg the error message (can be NULL) + */ static void create_finished (void *cls, int32_t success, const char *emsg) { @@ -369,6 +387,12 @@ create_finished (void *cls, int32_t success, const char *emsg) handle->add_qe = NULL; if (GNUNET_YES != success) { + if (NULL != emsg) + { + handle->emsg = GNUNET_strdup(emsg); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } handle->emsg = GNUNET_strdup("Error storing records"); GNUNET_SCHEDULER_add_now (&do_error, handle); return; @@ -379,6 +403,13 @@ create_finished (void *cls, int32_t success, const char *emsg) } +/** + * Delete finished callback + * + * @param cls the `struct RequestHandle` + * @param success the success indicating integer, GNUNET_OK on success + * @param emsg the error message (can be NULL) + */ static void del_finished (void *cls, int32_t success, const char *emsg) { @@ -387,12 +418,19 @@ del_finished (void *cls, int32_t success, const char *emsg) handle->add_qe = NULL; if (GNUNET_NO == success) { - handle->emsg = GNUNET_strdup("Deleting record failed. Record does not exist"); + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup("No record found"); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } if (GNUNET_SYSERR == success) { + if (NULL != emsg) + { + handle->emsg = GNUNET_strdup(emsg); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } handle->emsg = GNUNET_strdup("Deleting record failed"); GNUNET_SCHEDULER_add_now (&do_error, handle); return; @@ -452,17 +490,6 @@ namestore_list_iteration (void *cls, if (NULL == handle->resp_object) handle->resp_object = json_array(); - /*if ( (NULL != handle->ego_entry->identifier) && - (0 != strcmp (handle->ego_entry->identifier, - rname)) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%s does not match %s\n", rname, - handle->ego_entry->identifier); - GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1); - return; - }*/ - for (unsigned int i = 0; i < rd_len; i++) { if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) && @@ -495,40 +522,22 @@ namestore_get (struct GNUNET_REST_RequestHandle *con_handle, void *cls) { struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry = NULL; - struct GNUNET_HashCode key; - char *pubkey = NULL; - char *name = NULL; - - //change zone if pubkey or name specified - GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_PUBKEY, - strlen (GNUNET_REST_API_PARAM_PUBKEY), - &key); - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, - &key)) - { - pubkey = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, - &key); - } - GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_NAME, - strlen (GNUNET_REST_API_PARAM_NAME), - &key); - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, - &key)) - { - name = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, - &key); - } + struct EgoEntry *ego_entry; + char *egoname; + + egoname = NULL; + ego_entry = NULL; - ego_entry = get_egoentry(handle,pubkey,name); - if (NULL == ego_entry) + //set zone to name if given + if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url)) { - if (NULL != pubkey || NULL != name) + egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE)+1]; + ego_entry = get_egoentry_namestore(handle, egoname); + + if (NULL == ego_entry) { - handle->emsg = GNUNET_strdup("Invalid identity"); handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -537,6 +546,12 @@ namestore_get (struct GNUNET_REST_RequestHandle *con_handle, { handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego); } + if (NULL == handle->zone_pkey) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle, handle->zone_pkey, &namestore_iteration_error, @@ -545,53 +560,15 @@ namestore_get (struct GNUNET_REST_RequestHandle *con_handle, handle, &namestore_list_finished, handle); -} - - -/** - * We're storing a new record; this requires - * that no record already exists - * - * @param cls closure, unused - * @param zone_key private key of the zone - * @param rec_name name that is being mapped (at most 255 characters long) - * @param rd_count number of entries in @a rd array - * @param rd array of records with data to store - */ -static void -create_new_record_cont (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, - const char *rec_name, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct RequestHandle *handle = cls; - - handle->add_qe = NULL; - if (0 != strcmp (rec_name, handle->label_name)) + if (NULL == handle->list_it) { - GNUNET_break (0); + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - - if (0 != rd_count) - { - handle->proc (handle->proc_cls, - GNUNET_REST_create_response (NULL), - MHD_HTTP_CONFLICT); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); - return; - } - handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle, - handle->zone_pkey, - handle->label_name, - GNUNET_REST_NAMESTORE_RD_COUNT, - handle->rd, - &create_finished, - handle); } + /** * Handle namestore POST request * @@ -606,30 +583,21 @@ namestore_add (struct GNUNET_REST_RequestHandle *con_handle, { struct RequestHandle *handle = cls; struct GNUNET_GNSRECORD_Data *gns_record; + struct EgoEntry *ego_entry; + char *egoname; json_t *data_js; json_t *name_json; json_error_t err; - - struct EgoEntry *ego_entry = NULL; - struct GNUNET_HashCode key; - char *pubkey = NULL; - char *name = NULL; - char term_data[handle->rest_handle->data_size + 1]; + struct GNUNET_JSON_Specification gnsspec[] = { GNUNET_JSON_spec_gnsrecord_data(&gns_record), GNUNET_JSON_spec_end () }; - if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url)) - { - handle->emsg = GNUNET_strdup("Wrong URL"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } if (0 >= handle->rest_handle->data_size) { - handle->emsg = GNUNET_strdup("No data"); + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DATA); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -639,7 +607,7 @@ namestore_add (struct GNUNET_REST_RequestHandle *con_handle, data_js = json_loads (term_data, JSON_DECODE_ANY, &err); if (GNUNET_OK != GNUNET_JSON_parse (data_js, gnsspec, NULL, NULL)) { - handle->emsg = GNUNET_strdup("Invalid data"); + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA); GNUNET_SCHEDULER_add_now (&do_error, handle); GNUNET_JSON_parse_free(gnsspec); json_decref (data_js); @@ -647,109 +615,74 @@ namestore_add (struct GNUNET_REST_RequestHandle *con_handle, } handle->rd = gns_record; - name_json = json_object_get(data_js, "label"); + name_json = json_object_get(data_js, "record_name"); if (!json_is_string(name_json)) { - handle->emsg = GNUNET_strdup("Missing name"); + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA); GNUNET_SCHEDULER_add_now (&do_error, handle); json_decref (data_js); return; } - handle->label_name = GNUNET_strdup(json_string_value(name_json)); - if(NULL == handle->label_name) + handle->record_name = GNUNET_strdup(json_string_value(name_json)); + if(NULL == handle->record_name) { - handle->emsg = GNUNET_strdup("Missing name"); + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA); GNUNET_SCHEDULER_add_now (&do_error, handle); json_decref (data_js); return; } - if (0 >= strlen(handle->label_name)) + if (0 >= strlen(handle->record_name)) { - handle->emsg = GNUNET_strdup("Missing name"); + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA); GNUNET_SCHEDULER_add_now (&do_error, handle); json_decref (data_js); return; } json_decref (data_js); - //change zone if pubkey or name specified - GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_PUBKEY, - strlen (GNUNET_REST_API_PARAM_PUBKEY), - &key); - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, - &key)) - { - pubkey = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, - &key); - } - GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_NAME, - strlen (GNUNET_REST_API_PARAM_NAME), - &key); - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, - &key)) - { - name = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, - &key); - } + egoname = NULL; + ego_entry = NULL; - ego_entry = get_egoentry(handle,pubkey,name); - if (NULL == ego_entry) + //set zone to name if given + if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url)) { - if (NULL != pubkey || NULL != name) + egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE)+1]; + ego_entry = get_egoentry_namestore(handle, egoname); + + if (NULL == ego_entry) { - handle->emsg = GNUNET_strdup("Invalid identity"); handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } } - if ( NULL != ego_entry ) + if (NULL != ego_entry) { handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego); } if (NULL == handle->zone_pkey) { - handle->emsg = GNUNET_strdup("No default identity for namestore"); + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle, + handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle, handle->zone_pkey, - handle->label_name, - &do_error, - handle, - &create_new_record_cont, + handle->record_name, + 1, + handle->rd, + &create_finished, handle); -} - - -static void -del_cont (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, - const char *label, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct RequestHandle *handle = cls; - - handle->add_qe = NULL; - if (0 == rd_count) + if (NULL == handle->add_qe) { - handle->emsg = GNUNET_strdup("Record not found"); + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - - handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle, - handle->zone_pkey, - handle->label_name, - 0, NULL, - &del_finished, - handle); } + /** * Handle namestore DELETE request * @@ -764,39 +697,22 @@ namestore_delete (struct GNUNET_REST_RequestHandle *con_handle, { struct RequestHandle *handle = cls; struct GNUNET_HashCode key; - struct EgoEntry *ego_entry = NULL; - char *pubkey = NULL; - char *name = NULL; - - //change zone if pubkey or name specified - GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_PUBKEY, - strlen (GNUNET_REST_API_PARAM_PUBKEY), - &key); - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, - &key)) - { - pubkey = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, - &key); - } - GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_NAME, - strlen (GNUNET_REST_API_PARAM_NAME), - &key); - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, - &key)) - { - name = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, - &key); - } + struct EgoEntry *ego_entry; + char *egoname; + + egoname = NULL; + ego_entry = NULL; - ego_entry = get_egoentry(handle,pubkey,name); - if (NULL == ego_entry) + //set zone to name if given + if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url)) { - if (NULL != pubkey || NULL != name) + egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE)+1]; + ego_entry = get_egoentry_namestore(handle, egoname); + + if (NULL == ego_entry) { - handle->emsg = GNUNET_strdup("Invalid identity"); handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -806,33 +722,38 @@ namestore_delete (struct GNUNET_REST_RequestHandle *con_handle, handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego); } - GNUNET_CRYPTO_hash ("label", strlen ("label"), &key); + GNUNET_CRYPTO_hash ("record_name", strlen ("record_name"), &key); if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, &key)) { - handle->emsg = GNUNET_strdup("Missing name"); + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - handle->label_name = GNUNET_strdup( + handle->record_name = GNUNET_strdup( GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key)); if (NULL == handle->zone_pkey) { - handle->emsg = GNUNET_strdup("No default identity for namestore"); + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle, - handle->zone_pkey, - handle->label_name, - &do_error, - handle, - &del_cont, - handle); - + handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle, + handle->zone_pkey, + handle->record_name, + 0, + NULL, + &del_finished, + handle); + if (NULL == handle->add_qe) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } } @@ -916,7 +837,35 @@ default_ego_cb (void *cls, /** - * Connect to identity callback + * This function is initially called for all egos and then again + * whenever a ego's identifier changes or if it is deleted. At the + * end of the initial pass over all egos, the function is once called + * with 'NULL' for 'ego'. That does NOT mean that the callback won't + * be invoked in the future or that there was an error. + * + * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', + * this function is only called ONCE, and 'NULL' being passed in + * 'ego' does indicate an error (i.e. name is taken or no default + * value is known). If 'ego' is non-NULL and if '*ctx' + * is set in those callbacks, the value WILL be passed to a subsequent + * call to the identity callback of 'GNUNET_IDENTITY_connect' (if + * that one was not NULL). + * + * When an identity is renamed, this function is called with the + * (known) ego but the NEW identifier. + * + * When an identity is deleted, this function is called with the + * (known) ego and "NULL" for the 'identifier'. In this case, + * the 'ego' is henceforth invalid (and the 'ctx' should also be + * cleaned up). + * + * @param cls closure + * @param ego ego handle + * @param ctx context for application to store data for this ego + * (during the lifetime of this process, initially NULL) + * @param name identifier assigned by the user for this ego, + * NULL if the user just deleted the ego and it + * must thus no longer be used */ static void id_connect_cb (void *cls, @@ -931,7 +880,7 @@ id_connect_cb (void *cls, if ((NULL == ego) && (NULL == handle->zone_pkey)) { handle->op = GNUNET_IDENTITY_get (handle->identity_handle, - GNUNET_REST_SUBSYSTEM_NAMESTORE, + "namestore", &default_ego_cb, handle); } diff --git a/src/namestore/test_plugin_rest_namestore.sh b/src/namestore/test_plugin_rest_namestore.sh index de02dfafc..532c7caae 100755 --- a/src/namestore/test_plugin_rest_namestore.sh +++ b/src/namestore/test_plugin_rest_namestore.sh @@ -11,7 +11,7 @@ curl_get () { #$1 is link #$2 is grep cache="$(curl -v "$1" 2>&1 | grep "$2")" - #echo $cache + echo $cache if [ "" == "$cache" ] then exit 1 @@ -23,7 +23,7 @@ curl_post () { #$2 is data #$3 is grep cache="$(curl -v -X "POST" "$1" --data "$2" 2>&1 | grep "$3")" - #echo $cache + echo $cache if [ "" == "$cache" ] then exit 1 @@ -34,7 +34,7 @@ curl_delete () { #$1 is link #$2 is grep cache="$(curl -v -X "DELETE" "$1" 2>&1 | grep "$2")" - #echo $cache + echo $cache if [ "" == "$cache" ] then exit 1 @@ -64,141 +64,80 @@ public="$(gnunet-identity -d | grep "test_plugin_rest_namestore" | awk 'NR==1{pr if [ "" == "$test" ] then #if no entries for test_plugin_rest_namestore - curl_get "${namestore_link}?name=$name" "error" - curl_get "${namestore_link}?name=" "error" - curl_get "${namestore_link}?name=$public" "error" - - curl_get "${namestore_link}?pubkey=$public" "error" - curl_get "${namestore_link}?pubkey=$name" "error" - curl_get "${namestore_link}?pubkey=" "error" + curl_get "${namestore_link}/$name" "error" + curl_get "${namestore_link}/" "error" + curl_get "${namestore_link}/$public" "error" else #if entries exists (that should not be possible) curl_get "${namestore_link}" "HTTP/1.1 200 OK" - curl_get "${namestore_link}?name=$name" "HTTP/1.1 200 OK" - curl_get "${namestore_link}?name=" "error" - curl_get "${namestore_link}?name=$public" "error" - - curl_get "${namestore_link}?pubkey=$public" "HTTP/1.1 200 OK" - curl_get "${namestore_link}?pubkey=$name" "error" - curl_get "${namestore_link}?pubkey=" "error" + curl_get "${namestore_link}/$name" "HTTP/1.1 200 OK" + curl_get "${namestore_link}/" "error" + curl_get "${namestore_link}/$public" "error" fi gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" curl_get "${namestore_link}" "HTTP/1.1 200 OK" -curl_get "${namestore_link}?name=$name" "HTTP/1.1 200 OK" -curl_get "${namestore_link}?name=" "error" -curl_get "${namestore_link}?name=$public" "error" -curl_get "${namestore_link}?pubkey=$public" "HTTP/1.1 200 OK" -curl_get "${namestore_link}?pubkey=$name" "error" -curl_get "${namestore_link}?pubkey=" "error" +curl_get "${namestore_link}/$name" "HTTP/1.1 200 OK" +curl_get "${namestore_link}/" "error" +curl_get "${namestore_link}/$public" "error" gnunet-namestore -z $name -d -n "test_entry" #Test POST with NAME -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 #value -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?name=$name" '{"value":"", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error" +curl_post "${namestore_link}/$name" '{"value":"", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?name=$name" '{"value_missing":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error" +curl_post "${namestore_link}/$name" '{"value_missing":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 #time -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"0d","flag":0,"label":"test_entry"}' "HTTP/1.1 204" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"0d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"10000d","flag":0,"label":"test_entry"}' "HTTP/1.1 204" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"10000d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"now","flag":0,"label":"test_entry"}' "error" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"now","flag":0,"record_name":"test_entry"}' "error" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"","flag":0,"label":"test_entry"}' "error" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"","flag":0,"record_name":"test_entry"}' "error" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time_missing":"1d","flag":0,"label":"test_entry"}' "error" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time_missing":"1d","flag":0,"record_name":"test_entry"}' "error" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 #flag -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":2,"label":"test_entry"}' "HTTP/1.1 204 No Content" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":2,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":8,"label":"test_entry"}' "HTTP/1.1 204 No Content" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":8,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":16,"label":"test_entry"}' "HTTP/1.1 204 No Content" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":16,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":-1,"label":"test_entry"}' "error" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":-1,"record_name":"test_entry"}' "error" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":"Test","label":"test_entry"}' "error" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":"Test","record_name":"test_entry"}' "error" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":,"label":"test_entry"}' "error" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":,"record_name":"test_entry"}' "error" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag_missing":0,"label":"test_entry"}' "error" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag_missing":0,"record_name":"test_entry"}' "error" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -#label -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content" -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 409" +#record_name +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":""}' "error" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":""}' "error" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label_missing":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 - -#Test POST with PUBKEY -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -#value -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$public" '{"value":"", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$public" '{"value_missing":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -#time -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"0d","flag":0,"label":"test_entry"}' "HTTP/1.1 204" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"10000d","flag":0,"label":"test_entry"}' "HTTP/1.1 204" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"now","flag":0,"label":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"","flag":0,"label":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time_missing":"1d","flag":0,"label":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -#flag -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":2,"label":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":8,"label":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":16,"label":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":-1,"label":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":"Test","label":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":,"label":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag_missing":0,"label":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -#label -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content" -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 409" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":""}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label_missing":"test_entry"}' "error" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name_missing":"test_entry"}' "error" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 #wrong zone -curl_post "${namestore_link}?name=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}?pubkey=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error" +curl_post "${namestore_link}/$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 #Test DELETE gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" -curl_delete "${namestore_link}?label=test_entry&name=$name" "HTTP/1.1 204" -gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" -curl_delete "${namestore_link}?label=test_entry&pubkey=$public" "HTTP/1.1 204" +curl_delete "${namestore_link}/$name?record_name=test_entry" "HTTP/1.1 204" +curl_delete "${namestore_link}/$name?record_name=test_entry" "error" gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" -curl_delete "${namestore_link}?label=test_entry&pubkey=$name" "HTTP/1.1 404" +curl_delete "${namestore_link}/$public?record_name=test_entry" "error" #Test default identity diff --git a/src/peerinfo/plugin_rest_peerinfo.c b/src/peerinfo/plugin_rest_peerinfo.c index 97c473e36..e34bde9f5 100644 --- a/src/peerinfo/plugin_rest_peerinfo.c +++ b/src/peerinfo/plugin_rest_peerinfo.c @@ -31,13 +31,30 @@ #include "microhttpd.h" #include +/** + * Peerinfo Namespace + */ #define GNUNET_REST_API_NS_PEERINFO "/peerinfo" -#define GNUNET_REST_API_PEERINFO_PEER "peer" -#define GNUNET_REST_API_PEERINFO_FRIEND "friend" -#define GNUNET_REST_API_PEERINFO_ARRAY "array" +/** + * Peerinfo parameter peer + */ +#define GNUNET_REST_PEERINFO_PEER "peer" -#define GNUNET_REST_ERROR_UNKNOWN "Unkown Error" +/** + * Peerinfo parameter friend + */ +#define GNUNET_REST_PEERINFO_FRIEND "friend" + +/** + * Peerinfo parameter array + */ +#define GNUNET_REST_PEERINFO_ARRAY "array" + +/** + * Error message Unknown Error + */ +#define GNUNET_REST_PEERINFO_ERROR_UNKNOWN "Unknown Error" /** * How long until we time out during address lookup? @@ -94,7 +111,6 @@ struct AddressRecord */ struct PrintContext { - /** * Kept in DLL. */ @@ -152,6 +168,9 @@ static struct PrintContext *pc_head; */ static struct PrintContext *pc_tail; +/** + * The request handle + */ struct RequestHandle { /** @@ -299,7 +318,7 @@ do_error (void *cls) char *response; if (NULL == handle->emsg) - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_UNKNOWN); + handle->emsg = GNUNET_strdup(GNUNET_REST_PEERINFO_ERROR_UNKNOWN); json_object_set_new(json_error,"error", json_string(handle->emsg)); @@ -315,7 +334,9 @@ do_error (void *cls) /** - * Function that assembles our response. + * Function that assembles the response. + * + * @param cls the `struct RequestHandle` */ static void peerinfo_list_finished (void *cls) @@ -326,6 +347,7 @@ peerinfo_list_finished (void *cls) if (NULL == handle->response) { + handle->response_code = MHD_HTTP_NOT_FOUND; handle->emsg = GNUNET_strdup ("No peers found"); GNUNET_SCHEDULER_add_now (&do_error, handle); return; @@ -386,9 +408,6 @@ dump_pc (struct PrintContext *pc) temp_array = json_array(); response_entry = json_object(); -// printf (_("%sPeer `%s'\n"), -// (GNUNET_YES == pc->friend_only) ? "F2F: " : "", -// GNUNET_i2s_full (&pc->peer)); for (i = 0; i < pc->num_addresses; i++) { if (NULL != pc->address_list[i].result) @@ -417,10 +436,10 @@ dump_pc (struct PrintContext *pc) GNUNET_i2s_full (&pc->peer)); friend_and_peer_json = json_string(friend_and_peer); json_object_set(response_entry, - GNUNET_REST_API_PEERINFO_PEER, + GNUNET_REST_PEERINFO_PEER, friend_and_peer_json); json_object_set(response_entry, - GNUNET_REST_API_PEERINFO_ARRAY, + GNUNET_REST_PEERINFO_ARRAY, temp_array); json_array_append(pc->handle->response, response_entry); json_decref(friend_and_peer_json); @@ -615,8 +634,8 @@ peerinfo_get (struct GNUNET_REST_RequestHandle *con_handle, char* include_friend_only_str; include_friend_only = GNUNET_NO; - GNUNET_CRYPTO_hash (GNUNET_REST_API_PEERINFO_FRIEND, - strlen (GNUNET_REST_API_PEERINFO_FRIEND), + GNUNET_CRYPTO_hash (GNUNET_REST_PEERINFO_FRIEND, + strlen (GNUNET_REST_PEERINFO_FRIEND), &key); if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, @@ -631,15 +650,15 @@ peerinfo_get (struct GNUNET_REST_RequestHandle *con_handle, } specific_peer = NULL; - GNUNET_CRYPTO_hash (GNUNET_REST_API_PEERINFO_PEER, - strlen (GNUNET_REST_API_PEERINFO_PEER), + GNUNET_CRYPTO_hash (GNUNET_REST_PEERINFO_PEER, + strlen (GNUNET_REST_PEERINFO_PEER), &key); if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, &key)) { - peer_id = *(unsigned int*)GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key); - specific_peer = GNUNET_PEER_resolve2(peer_id); + //peer_id = *(unsigned int*)GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key); + //specific_peer = GNUNET_PEER_resolve2(peer_id); } handle->list_it = GNUNET_PEERINFO_iterate(handle->peerinfo_handle, -- cgit v1.2.3 From 6656d6c3e7111075572c042ae714c9710f30273b Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 12 Aug 2018 23:37:32 +0200 Subject: -fix peerinfo warning --- src/peerinfo/plugin_rest_peerinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/peerinfo/plugin_rest_peerinfo.c b/src/peerinfo/plugin_rest_peerinfo.c index e34bde9f5..29b40088d 100644 --- a/src/peerinfo/plugin_rest_peerinfo.c +++ b/src/peerinfo/plugin_rest_peerinfo.c @@ -629,7 +629,7 @@ peerinfo_get (struct GNUNET_REST_RequestHandle *con_handle, struct RequestHandle *handle = cls; struct GNUNET_HashCode key; const struct GNUNET_PeerIdentity *specific_peer; - GNUNET_PEER_Id peer_id; + //GNUNET_PEER_Id peer_id; int include_friend_only; char* include_friend_only_str; -- cgit v1.2.3 From 6371b64774428e83ff83ada88bda354356718aca Mon Sep 17 00:00:00 2001 From: "Schanzenbach, Martin" Date: Mon, 13 Aug 2018 08:51:19 +0200 Subject: fix build; move rest plugins to separate folder --- configure.ac | 1 + po/POTFILES.in | 132 +- src/Makefile.am | 8 +- src/gns/Makefile.am | 19 - src/gns/plugin_rest_gns.c | 476 ------ src/identity/Makefile.am | 19 - src/identity/plugin_rest_identity.c | 1319 --------------- src/jsonapi/Makefile.am | 18 +- src/jsonapi/plugin_rest_reclaim.c | 1253 ++++++++++++++ src/namestore/Makefile.am | 23 +- src/namestore/plugin_rest_namestore.c | 1004 ------------ src/peerinfo/Makefile.am | 20 - src/peerinfo/plugin_rest_peerinfo.c | 820 ---------- src/reclaim/Makefile.am | 33 - src/reclaim/oidc_helper.c | 440 ----- src/reclaim/oidc_helper.h | 109 -- src/reclaim/plugin_rest_openid_connect.c | 2171 ------------------------- src/reclaim/plugin_rest_reclaim.c | 1253 -------------- src/rest-plugins/Makefile.am | 102 ++ src/rest-plugins/oidc_helper.c | 440 +++++ src/rest-plugins/oidc_helper.h | 109 ++ src/rest-plugins/plugin_rest_copying.c | 231 +++ src/rest-plugins/plugin_rest_gns.c | 476 ++++++ src/rest-plugins/plugin_rest_identity.c | 1319 +++++++++++++++ src/rest-plugins/plugin_rest_namestore.c | 1004 ++++++++++++ src/rest-plugins/plugin_rest_openid_connect.c | 2171 +++++++++++++++++++++++++ src/rest-plugins/plugin_rest_peerinfo.c | 820 ++++++++++ src/rest/Makefile.am | 13 - src/rest/plugin_rest_copying.c | 231 --- 29 files changed, 8013 insertions(+), 8021 deletions(-) delete mode 100644 src/gns/plugin_rest_gns.c delete mode 100644 src/identity/plugin_rest_identity.c create mode 100644 src/jsonapi/plugin_rest_reclaim.c delete mode 100644 src/namestore/plugin_rest_namestore.c delete mode 100644 src/peerinfo/plugin_rest_peerinfo.c delete mode 100644 src/reclaim/oidc_helper.c delete mode 100644 src/reclaim/oidc_helper.h delete mode 100644 src/reclaim/plugin_rest_openid_connect.c delete mode 100644 src/reclaim/plugin_rest_reclaim.c create mode 100644 src/rest-plugins/Makefile.am create mode 100644 src/rest-plugins/oidc_helper.c create mode 100644 src/rest-plugins/oidc_helper.h create mode 100644 src/rest-plugins/plugin_rest_copying.c create mode 100644 src/rest-plugins/plugin_rest_gns.c create mode 100644 src/rest-plugins/plugin_rest_identity.c create mode 100644 src/rest-plugins/plugin_rest_namestore.c create mode 100644 src/rest-plugins/plugin_rest_openid_connect.c create mode 100644 src/rest-plugins/plugin_rest_peerinfo.c delete mode 100644 src/rest/plugin_rest_copying.c (limited to 'src') diff --git a/configure.ac b/configure.ac index 535ce0ffe..6a75b1ebf 100644 --- a/configure.ac +++ b/configure.ac @@ -1758,6 +1758,7 @@ src/vpn/vpn.conf src/zonemaster/Makefile src/zonemaster/zonemaster.conf src/rest/Makefile +src/rest-plugins/Makefile src/abe/Makefile src/reclaim-attribute/Makefile src/reclaim/Makefile diff --git a/po/POTFILES.in b/po/POTFILES.in index 070ecc4ce..a1cdac7f2 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -4,13 +4,21 @@ src/arm/arm_monitor_api.c src/arm/gnunet-arm.c src/arm/gnunet-service-arm.c src/arm/mockup-service.c +src/ats-tests/ats-testing-experiment.c +src/ats-tests/ats-testing-log.c +src/ats-tests/ats-testing-preferences.c +src/ats-tests/ats-testing-traffic.c +src/ats-tests/ats-testing.c +src/ats-tests/gnunet-ats-sim.c +src/ats-tests/gnunet-solver-eval.c +src/ats-tool/gnunet-ats.c src/ats/ats_api_connectivity.c src/ats/ats_api_performance.c src/ats/ats_api_scanner.c src/ats/ats_api_scheduling.c src/ats/gnunet-ats-solver-eval.c -src/ats/gnunet-service-ats_addresses.c src/ats/gnunet-service-ats.c +src/ats/gnunet-service-ats_addresses.c src/ats/gnunet-service-ats_connectivity.c src/ats/gnunet-service-ats_normalization.c src/ats/gnunet-service-ats_performance.c @@ -21,14 +29,6 @@ src/ats/gnunet-service-ats_scheduling.c src/ats/plugin_ats_mlp.c src/ats/plugin_ats_proportional.c src/ats/plugin_ats_ril.c -src/ats-tests/ats-testing.c -src/ats-tests/ats-testing-experiment.c -src/ats-tests/ats-testing-log.c -src/ats-tests/ats-testing-preferences.c -src/ats-tests/ats-testing-traffic.c -src/ats-tests/gnunet-ats-sim.c -src/ats-tests/gnunet-solver-eval.c -src/ats-tool/gnunet-ats.c src/auction/gnunet-auction-create.c src/auction/gnunet-auction-info.c src/auction/gnunet-auction-join.c @@ -40,8 +40,8 @@ src/block/plugin_block_test.c src/cadet/cadet_api.c src/cadet/cadet_test_lib.c src/cadet/desirability_table.c -src/cadet/gnunet-cadet.c src/cadet/gnunet-cadet-profiler.c +src/cadet/gnunet-cadet.c src/cadet/gnunet-service-cadet.c src/cadet/gnunet-service-cadet_channel.c src/cadet/gnunet-service-cadet_connection.c @@ -57,15 +57,15 @@ src/consensus/gnunet-service-consensus.c src/consensus/plugin_block_consensus.c src/conversation/conversation_api.c src/conversation/conversation_api_call.c -src/conversation/gnunet-conversation.c src/conversation/gnunet-conversation-test.c -src/conversation/gnunet_gst.c -src/conversation/gnunet_gst_test.c -src/conversation/gnunet-helper-audio-playback.c +src/conversation/gnunet-conversation.c src/conversation/gnunet-helper-audio-playback-gst.c -src/conversation/gnunet-helper-audio-record.c +src/conversation/gnunet-helper-audio-playback.c src/conversation/gnunet-helper-audio-record-gst.c +src/conversation/gnunet-helper-audio-record.c src/conversation/gnunet-service-conversation.c +src/conversation/gnunet_gst.c +src/conversation/gnunet_gst_test.c src/conversation/microphone.c src/conversation/plugin_gnsrecord_conversation.c src/conversation/speaker.c @@ -102,7 +102,6 @@ src/dht/dht_api.c src/dht/dht_test_lib.c src/dht/gnunet-dht-get.c src/dht/gnunet-dht-monitor.c -src/dht/gnunet_dht_profiler.c src/dht/gnunet-dht-put.c src/dht/gnunet-service-dht.c src/dht/gnunet-service-dht_clients.c @@ -111,6 +110,7 @@ src/dht/gnunet-service-dht_hello.c src/dht/gnunet-service-dht_neighbours.c src/dht/gnunet-service-dht_nse.c src/dht/gnunet-service-dht_routing.c +src/dht/gnunet_dht_profiler.c src/dht/plugin_block_dht.c src/dns/dns_api.c src/dns/gnunet-dns-monitor.c @@ -124,8 +124,8 @@ src/dv/gnunet-dv.c src/dv/gnunet-service-dv.c src/dv/plugin_transport_dv.c src/exit/gnunet-daemon-exit.c -src/exit/gnunet-helper-exit.c src/exit/gnunet-helper-exit-windows.c +src/exit/gnunet-helper-exit.c src/fragmentation/defragmentation.c src/fragmentation/fragmentation.c src/fs/fs_api.c @@ -150,8 +150,8 @@ src/fs/gnunet-auto-share.c src/fs/gnunet-daemon-fsprofiler.c src/fs/gnunet-directory.c src/fs/gnunet-download.c -src/fs/gnunet-fs.c src/fs/gnunet-fs-profiler.c +src/fs/gnunet-fs.c src/fs/gnunet-helper-fs-publish.c src/fs/gnunet-publish.c src/fs/gnunet-search.c @@ -171,10 +171,10 @@ src/gns/gns_tld_api.c src/gns/gnunet-bcd.c src/gns/gnunet-dns2gns.c src/gns/gnunet-gns-benchmark.c -src/gns/gnunet-gns.c src/gns/gnunet-gns-helper-service-w32.c src/gns/gnunet-gns-import.c src/gns/gnunet-gns-proxy.c +src/gns/gnunet-gns.c src/gns/gnunet-service-gns.c src/gns/gnunet-service-gns_interceptor.c src/gns/gnunet-service-gns_resolver.c @@ -182,16 +182,15 @@ src/gns/nss/nss_gns.c src/gns/nss/nss_gns_query.c src/gns/plugin_block_gns.c src/gns/plugin_gnsrecord_gns.c -src/gns/plugin_rest_gns.c +src/gns/w32nsp-install.c +src/gns/w32nsp-resolve.c +src/gns/w32nsp-uninstall.c +src/gns/w32nsp.c src/gnsrecord/gnsrecord.c src/gnsrecord/gnsrecord_crypto.c src/gnsrecord/gnsrecord_misc.c src/gnsrecord/gnsrecord_serialization.c src/gnsrecord/plugin_gnsrecord_dns.c -src/gns/w32nsp.c -src/gns/w32nsp-install.c -src/gns/w32nsp-resolve.c -src/gns/w32nsp-uninstall.c src/hello/address.c src/hello/gnunet-hello.c src/hello/hello.c @@ -202,17 +201,18 @@ src/identity/gnunet-identity.c src/identity/gnunet-service-identity.c src/identity/identity_api.c src/identity/identity_api_lookup.c -src/identity/plugin_rest_identity.c -src/jsonapi/jsonapi.c -src/jsonapi/jsonapi_document.c -src/jsonapi/jsonapi_error.c -src/jsonapi/jsonapi_relationship.c -src/jsonapi/jsonapi_resource.c src/json/json.c src/json/json_generator.c src/json/json_gnsrecord.c src/json/json_helper.c src/json/json_mhd.c +src/jsonapi/jsonapi.c +src/jsonapi/jsonapi_document.c +src/jsonapi/jsonapi_error.c +src/jsonapi/jsonapi_relationship.c +src/jsonapi/jsonapi_resource.c +src/jsonapi/plugin_rest_openid_connect.c +src/jsonapi/plugin_rest_reclaim.c src/multicast/gnunet-multicast.c src/multicast/gnunet-service-multicast.c src/multicast/multicast_api.c @@ -226,8 +226,8 @@ src/namecache/namecache_api.c src/namecache/plugin_namecache_flat.c src/namecache/plugin_namecache_postgres.c src/namecache/plugin_namecache_sqlite.c -src/namestore/gnunet-namestore.c src/namestore/gnunet-namestore-fcfsd.c +src/namestore/gnunet-namestore.c src/namestore/gnunet-service-namestore.c src/namestore/gnunet-zoneimport.c src/namestore/namestore_api.c @@ -235,7 +235,6 @@ src/namestore/namestore_api_monitor.c src/namestore/plugin_namestore_flat.c src/namestore/plugin_namestore_postgres.c src/namestore/plugin_namestore_sqlite.c -src/namestore/plugin_rest_namestore.c src/nat-auto/gnunet-nat-auto.c src/nat-auto/gnunet-nat-auto_legacy.c src/nat-auto/gnunet-nat-server.c @@ -243,10 +242,10 @@ src/nat-auto/gnunet-service-nat-auto.c src/nat-auto/gnunet-service-nat-auto_legacy.c src/nat-auto/nat_auto_api.c src/nat-auto/nat_auto_api_test.c -src/nat/gnunet-helper-nat-client.c src/nat/gnunet-helper-nat-client-windows.c -src/nat/gnunet-helper-nat-server.c +src/nat/gnunet-helper-nat-client.c src/nat/gnunet-helper-nat-server-windows.c +src/nat/gnunet-helper-nat-server.c src/nat/gnunet-nat.c src/nat/gnunet-service-nat.c src/nat/gnunet-service-nat_externalip.c @@ -255,16 +254,15 @@ src/nat/gnunet-service-nat_mini.c src/nat/gnunet-service-nat_stun.c src/nat/nat_api.c src/nat/nat_api_stun.c -src/nse/gnunet-nse.c src/nse/gnunet-nse-profiler.c +src/nse/gnunet-nse.c src/nse/gnunet-service-nse.c src/nse/nse_api.c +src/peerinfo-tool/gnunet-peerinfo.c +src/peerinfo-tool/gnunet-peerinfo_plugins.c src/peerinfo/gnunet-service-peerinfo.c src/peerinfo/peerinfo_api.c src/peerinfo/peerinfo_api_notify.c -src/peerinfo/plugin_rest_peerinfo.c -src/peerinfo-tool/gnunet-peerinfo.c -src/peerinfo-tool/gnunet-peerinfo_plugins.c src/peerstore/gnunet-peerstore.c src/peerstore/gnunet-service-peerstore.c src/peerstore/peerstore_api.c @@ -297,8 +295,6 @@ src/reclaim/jwt.c src/reclaim/oidc_helper.c src/reclaim/plugin_gnsrecord_reclaim.c src/reclaim/plugin_reclaim_sqlite.c -src/reclaim/plugin_rest_openid_connect.c -src/reclaim/plugin_rest_reclaim.c src/reclaim/reclaim_api.c src/regex/gnunet-daemon-regexprofiler.c src/regex/gnunet-regex-profiler.c @@ -314,27 +310,31 @@ src/regex/regex_internal_dht.c src/regex/regex_test_graph.c src/regex/regex_test_lib.c src/regex/regex_test_random.c +src/rest-plugins/plugin_rest_copying.c +src/rest-plugins/plugin_rest_gns.c +src/rest-plugins/plugin_rest_identity.c +src/rest-plugins/plugin_rest_namestore.c +src/rest-plugins/plugin_rest_peerinfo.c src/rest/gnunet-rest-server.c -src/rest/plugin_rest_copying.c src/rest/rest.c src/revocation/gnunet-revocation.c src/revocation/gnunet-service-revocation.c src/revocation/plugin_block_revocation.c src/revocation/revocation_api.c -src/rps/gnunet-rps.c src/rps/gnunet-rps-profiler.c +src/rps/gnunet-rps.c src/rps/gnunet-service-rps.c src/rps/gnunet-service-rps_custommap.c src/rps/gnunet-service-rps_sampler.c src/rps/gnunet-service-rps_sampler_elem.c src/rps/gnunet-service-rps_view.c -src/rps/rps_api.c src/rps/rps-test_util.c +src/rps/rps_api.c src/scalarproduct/gnunet-scalarproduct.c -src/scalarproduct/gnunet-service-scalarproduct_alice.c -src/scalarproduct/gnunet-service-scalarproduct_bob.c src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c +src/scalarproduct/gnunet-service-scalarproduct_alice.c +src/scalarproduct/gnunet-service-scalarproduct_bob.c src/scalarproduct/scalarproduct_api.c src/secretsharing/gnunet-secretsharing-profiler.c src/secretsharing/gnunet-service-secretsharing.c @@ -363,15 +363,16 @@ src/statistics/gnunet-statistics.c src/statistics/statistics_api.c src/template/gnunet-service-template.c src/template/gnunet-template.c +src/testbed-logger/gnunet-service-testbed-logger.c +src/testbed-logger/testbed_logger_api.c src/testbed/generate-underlay-topology.c src/testbed/gnunet-daemon-latency-logger.c src/testbed/gnunet-daemon-testbed-blacklist.c src/testbed/gnunet-daemon-testbed-underlay.c src/testbed/gnunet-helper-testbed.c -src/testbed/gnunet_mpi_test.c src/testbed/gnunet-service-test-barriers.c -src/testbed/gnunet-service-testbed_barriers.c src/testbed/gnunet-service-testbed.c +src/testbed/gnunet-service-testbed_barriers.c src/testbed/gnunet-service-testbed_cache.c src/testbed/gnunet-service-testbed_connectionpool.c src/testbed/gnunet-service-testbed_cpustatus.c @@ -379,20 +380,19 @@ src/testbed/gnunet-service-testbed_links.c src/testbed/gnunet-service-testbed_meminfo.c src/testbed/gnunet-service-testbed_oc.c src/testbed/gnunet-service-testbed_peers.c -src/testbed/gnunet_testbed_mpi_spawn.c src/testbed/gnunet-testbed-profiler.c -src/testbed-logger/gnunet-service-testbed-logger.c -src/testbed-logger/testbed_logger_api.c -src/testbed/testbed_api_barriers.c +src/testbed/gnunet_mpi_test.c +src/testbed/gnunet_testbed_mpi_spawn.c src/testbed/testbed_api.c +src/testbed/testbed_api_barriers.c src/testbed/testbed_api_hosts.c src/testbed/testbed_api_operations.c src/testbed/testbed_api_peers.c src/testbed/testbed_api_sd.c src/testbed/testbed_api_services.c src/testbed/testbed_api_statistics.c -src/testbed/testbed_api_testbed.c src/testbed/testbed_api_test.c +src/testbed/testbed_api_testbed.c src/testbed/testbed_api_topology.c src/testbed/testbed_api_underlay.c src/testing/gnunet-testing.c @@ -401,28 +401,28 @@ src/testing/testing.c src/topology/friends.c src/topology/gnunet-daemon-topology.c src/transport/gnunet-helper-transport-bluetooth.c -src/transport/gnunet-helper-transport-wlan.c src/transport/gnunet-helper-transport-wlan-dummy.c -src/transport/gnunet-service-transport_ats.c +src/transport/gnunet-helper-transport-wlan.c src/transport/gnunet-service-transport.c +src/transport/gnunet-service-transport_ats.c src/transport/gnunet-service-transport_hello.c src/transport/gnunet-service-transport_manipulation.c src/transport/gnunet-service-transport_neighbours.c src/transport/gnunet-service-transport_plugins.c src/transport/gnunet-service-transport_validation.c -src/transport/gnunet-transport.c src/transport/gnunet-transport-certificate-creation.c src/transport/gnunet-transport-profiler.c src/transport/gnunet-transport-wlan-receiver.c src/transport/gnunet-transport-wlan-sender.c +src/transport/gnunet-transport.c src/transport/plugin_transport_http_client.c src/transport/plugin_transport_http_common.c src/transport/plugin_transport_http_server.c src/transport/plugin_transport_smtp.c src/transport/plugin_transport_tcp.c src/transport/plugin_transport_template.c -src/transport/plugin_transport_udp_broadcasting.c src/transport/plugin_transport_udp.c +src/transport/plugin_transport_udp_broadcasting.c src/transport/plugin_transport_unix.c src/transport/plugin_transport_wlan.c src/transport/plugin_transport_xt.c @@ -431,6 +431,11 @@ src/transport/tcp_connection_legacy.c src/transport/tcp_server_legacy.c src/transport/tcp_server_mst_legacy.c src/transport/tcp_service_legacy.c +src/transport/transport-testing-filenames.c +src/transport/transport-testing-loggers.c +src/transport/transport-testing-main.c +src/transport/transport-testing-send.c +src/transport/transport-testing.c src/transport/transport_api_address_to_string.c src/transport/transport_api_blacklist.c src/transport/transport_api_core.c @@ -439,11 +444,6 @@ src/transport/transport_api_manipulation.c src/transport/transport_api_monitor_peers.c src/transport/transport_api_monitor_plugins.c src/transport/transport_api_offer_hello.c -src/transport/transport-testing.c -src/transport/transport-testing-filenames.c -src/transport/transport-testing-loggers.c -src/transport/transport-testing-main.c -src/transport/transport-testing-send.c src/util/bandwidth.c src/util/bio.c src/util/client.c @@ -455,8 +455,8 @@ src/util/configuration_loader.c src/util/container_bloomfilter.c src/util/container_heap.c src/util/container_meta_data.c -src/util/container_multihashmap32.c src/util/container_multihashmap.c +src/util/container_multihashmap32.c src/util/container_multipeermap.c src/util/container_multishortmap.c src/util/crypto_abe.c @@ -478,15 +478,15 @@ src/util/dnsparser.c src/util/dnsstub.c src/util/getopt.c src/util/getopt_helpers.c -src/util/gnunet-config.c src/util/gnunet-config-diff.c +src/util/gnunet-config.c src/util/gnunet-ecc.c src/util/gnunet-helper-w32-console.c src/util/gnunet-resolver.c src/util/gnunet-scrypt.c src/util/gnunet-service-resolver.c -src/util/gnunet-timeout.c src/util/gnunet-timeout-w32.c +src/util/gnunet-timeout.c src/util/gnunet-uri.c src/util/helper.c src/util/load.c @@ -514,13 +514,13 @@ src/util/tun.c src/util/w32cat.c src/util/win.c src/util/winproc.c -src/vpn/gnunet-helper-vpn.c src/vpn/gnunet-helper-vpn-windows.c +src/vpn/gnunet-helper-vpn.c src/vpn/gnunet-service-vpn.c src/vpn/gnunet-vpn.c src/vpn/vpn_api.c -src/zonemaster/gnunet-service-zonemaster.c src/zonemaster/gnunet-service-zonemaster-monitor.c +src/zonemaster/gnunet-service-zonemaster.c src/fs/fs_api.h src/include/gnunet_common.h src/include/gnunet_mq_lib.h diff --git a/src/Makefile.am b/src/Makefile.am index 53d157da3..43b1004eb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -65,9 +65,8 @@ if HAVE_POSTGRESQL endif if HAVE_MHD - REST_DIR = rest if HAVE_JSON - JSONAPI_DIR = jsonapi + REST_DIR = rest jsonapi rest-plugins endif endif @@ -82,9 +81,6 @@ SUBDIRS = \ include $(INTLEMU_SUBDIRS) \ util \ gnsrecord \ - $(JSON_DIR) \ - $(REST_DIR) \ - $(JSONAPI_DIR) \ hello \ block \ statistics \ @@ -130,6 +126,8 @@ SUBDIRS = \ exit \ pt \ secretsharing \ + $(JSON_DIR) \ + $(REST_DIR) \ integration-tests \ $(EXP_DIR) diff --git a/src/gns/Makefile.am b/src/gns/Makefile.am index 2c7bb8ebb..2659f7e6a 100644 --- a/src/gns/Makefile.am +++ b/src/gns/Makefile.am @@ -92,12 +92,6 @@ plugin_LTLIBRARIES = \ libgnunet_plugin_gnsrecord_gns.la -if HAVE_MHD -if HAVE_JSON -plugin_LTLIBRARIES += libgnunet_plugin_rest_gns.la -endif -endif - libgnunet_plugin_gnsrecord_gns_la_SOURCES = \ plugin_gnsrecord_gns.c libgnunet_plugin_gnsrecord_gns_la_LIBADD = \ @@ -238,19 +232,6 @@ libgnunet_plugin_block_gns_la_LIBADD = \ libgnunet_plugin_block_gns_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) -libgnunet_plugin_rest_gns_la_SOURCES = \ - plugin_rest_gns.c -libgnunet_plugin_rest_gns_la_LIBADD = \ - libgnunetgns.la \ - $(top_builddir)/src/rest/libgnunetrest.la \ - $(top_builddir)/src/identity/libgnunetidentity.la \ - $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \ - $(top_builddir)/src/jsonapi/libgnunetjsonapiutils.la \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -ljansson -lmicrohttpd -libgnunet_plugin_rest_gns_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - check_SCRIPTS = \ test_gns_lookup.sh \ diff --git a/src/gns/plugin_rest_gns.c b/src/gns/plugin_rest_gns.c deleted file mode 100644 index 0bf4198fc..000000000 --- a/src/gns/plugin_rest_gns.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -/** - * @author Philippe Buschmann - * @file gns/plugin_rest_gns.c - * @brief GNUnet Gns REST plugin - */ - -#include "platform.h" -#include "gnunet_rest_plugin.h" -#include "gnunet_rest_lib.h" -#include "gnunet_json_lib.h" -#include "gnunet_gnsrecord_lib.h" -#include "gnunet_gns_service.h" -#include "microhttpd.h" -#include - -/** - * Rest API GNS Namespace - */ -#define GNUNET_REST_API_NS_GNS "/gns" - -/** - * Rest API GNS Parameter record_type - */ -#define GNUNET_REST_GNS_PARAM_RECORD_TYPE "record_type" - -/** - * Rest API GNS ERROR Unknown Error - */ -#define GNUNET_REST_GNS_ERROR_UNKNOWN "Unknown Error" - -/** - * Rest API GNS ERROR Record not found - */ -#define GNUNET_REST_GNS_NOT_FOUND "Record not found" - -/** - * The configuration handle - */ -const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * HTTP methods allows for this plugin - */ -static char* allow_methods; - -/** - * @brief struct returned by the initialization function of the plugin - */ -struct Plugin -{ - const struct GNUNET_CONFIGURATION_Handle *cfg; -}; - -/** - * The request handle - */ -struct RequestHandle -{ - - /** - * Connection to GNS - */ - struct GNUNET_GNS_Handle *gns; - - /** - * Active GNS lookup - */ - struct GNUNET_GNS_LookupWithTldRequest *gns_lookup; - - /** - * Name to look up - */ - char *name; - - /** - * Record type to look up - */ - int record_type; - - /** - * Rest connection - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * Desired timeout for the lookup (default is no timeout). - */ - struct GNUNET_TIME_Relative timeout; - - /** - * ID of a task associated with the resolution process. - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * The url - */ - char *url; - - /** - * Error response message - */ - char *emsg; - - /** - * Response code - */ - int response_code; - -}; - - -/** - * Cleanup lookup handle - * @param handle Handle to clean up - */ -static void -cleanup_handle (void *cls) -{ - struct RequestHandle *handle = cls; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Cleaning up\n"); - - if (NULL != handle->gns_lookup) - { - GNUNET_GNS_lookup_with_tld_cancel (handle->gns_lookup); - handle->gns_lookup = NULL; - } - if (NULL != handle->gns) - { - GNUNET_GNS_disconnect (handle->gns); - handle->gns = NULL; - } - - if (NULL != handle->timeout_task) - { - GNUNET_SCHEDULER_cancel (handle->timeout_task); - handle->timeout_task = NULL; - } - if (NULL != handle->url) - GNUNET_free (handle->url); - if (NULL != handle->name) - GNUNET_free (handle->name); - if (NULL != handle->emsg) - GNUNET_free (handle->emsg); - - GNUNET_free (handle); -} - - -/** - * Task run on errors. Reports an error and cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - json_t *json_error = json_object(); - char *response; - - if (NULL == handle->emsg) - handle->emsg = GNUNET_strdup(GNUNET_REST_GNS_ERROR_UNKNOWN); - - json_object_set_new(json_error,"error", json_string(handle->emsg)); - - if (0 == handle->response_code) - handle->response_code = MHD_HTTP_OK; - response = json_dumps (json_error, 0); - resp = GNUNET_REST_create_response (response); - handle->proc (handle->proc_cls, resp, handle->response_code); - json_decref(json_error); - GNUNET_free(response); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Iterator called on obtained result for a GNS lookup. - * - * @param cls closure with the object - * @param was_gns #GNUNET_NO if name was not a GNS name - * @param rd_count number of records in @a rd - * @param rd the records in reply - */ -static void -handle_gns_response (void *cls, - int was_gns, - uint32_t rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - json_t *result_array; - json_t *record_obj; - char *result; - - handle->gns_lookup = NULL; - - if (GNUNET_NO == was_gns) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_GNS_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - result_array = json_array(); - for (uint32_t i=0;irecord_type) && - (GNUNET_GNSRECORD_TYPE_ANY != handle->record_type) ) - { - continue; - } - - record_obj = GNUNET_JSON_from_gns_record(NULL,&rd[i]); - json_array_append (result_array, record_obj); - json_decref (record_obj); - } - - result = json_dumps(result_array, 0); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result); - resp = GNUNET_REST_create_response (result); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free (result); - json_decref (result_array); - GNUNET_SCHEDULER_add_now(&cleanup_handle, handle); -} - - -/** - * Handle gns GET request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -get_gns_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_HashCode key; - char *record_type; - char *name; - - name = NULL; - handle->name = NULL; - if (strlen (GNUNET_REST_API_NS_GNS) < strlen (handle->url)) - { - name = &handle->url[strlen (GNUNET_REST_API_NS_GNS) + 1]; - } - - if (NULL == name) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_GNS_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (0 >= strlen (name)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_GNS_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->name = GNUNET_strdup(name); - - handle->record_type = UINT32_MAX; - GNUNET_CRYPTO_hash (GNUNET_REST_GNS_PARAM_RECORD_TYPE, - strlen (GNUNET_REST_GNS_PARAM_RECORD_TYPE), - &key); - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, - &key)) - { - record_type = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key); - handle->record_type = GNUNET_GNSRECORD_typename_to_number(record_type); - } - - if(UINT32_MAX == handle->record_type) - { - handle->record_type = GNUNET_GNSRECORD_TYPE_ANY; - } - - handle->gns_lookup = GNUNET_GNS_lookup_with_tld (handle->gns, - handle->name, - handle->record_type, - GNUNET_NO, - &handle_gns_response, - handle); -} - - - -/** - * Respond to OPTIONS request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -options_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - //independent of path return all options - resp = GNUNET_REST_create_response (NULL); - MHD_add_response_header (resp, - "Access-Control-Allow-Methods", - allow_methods); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_SCHEDULER_add_now(&cleanup_handle, handle); - return; -} - - -/** - * Handle rest request - * - * @param handle the request handle - */ -static void -init_cont (struct RequestHandle *handle) -{ - struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = { - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_GNS, &get_gns_cont}, - {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_GNS, &options_cont}, - GNUNET_REST_HANDLER_END - }; - - if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, - handlers, - &err, - handle)) - { - handle->response_code = err.error_code; - GNUNET_SCHEDULER_add_now (&do_error, handle); - } -} - - -/** - * Function processing the REST call - * - * @param method HTTP method - * @param url URL of the HTTP request - * @param data body of the HTTP request (optional) - * @param data_size length of the body - * @param proc callback function for the result - * @param proc_cls closure for callback function - * @return GNUNET_OK if request accepted - */ -static void -rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) -{ - struct RequestHandle *handle = GNUNET_new (struct RequestHandle); - - handle->response_code = 0; - handle->timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60); - handle->proc_cls = proc_cls; - handle->proc = proc; - handle->rest_handle = rest_handle; - - handle->url = GNUNET_strdup (rest_handle->url); - if (handle->url[strlen (handle->url)-1] == '/') - handle->url[strlen (handle->url)-1] = '\0'; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); - handle->gns = GNUNET_GNS_connect (cfg); - init_cont(handle); - - handle->timeout_task = - GNUNET_SCHEDULER_add_delayed (handle->timeout, - &do_error, - handle); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); -} - - -/** - * Entry point for the plugin. - * - * @param cls Config info - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_rest_gns_init (void *cls) -{ - static struct Plugin plugin; - struct GNUNET_REST_Plugin *api; - - cfg = cls; - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof (struct Plugin)); - plugin.cfg = cfg; - api = GNUNET_new (struct GNUNET_REST_Plugin); - api->cls = &plugin; - api->name = GNUNET_REST_API_NS_GNS; - api->process_request = &rest_process_request; - GNUNET_asprintf (&allow_methods, - "%s, %s, %s, %s, %s", - MHD_HTTP_METHOD_GET, - MHD_HTTP_METHOD_POST, - MHD_HTTP_METHOD_PUT, - MHD_HTTP_METHOD_DELETE, - MHD_HTTP_METHOD_OPTIONS); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _("Gns REST API initialized\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ -void * -libgnunet_plugin_rest_gns_done (void *cls) -{ - struct GNUNET_REST_Plugin *api = cls; - struct Plugin *plugin = api->cls; - plugin->cfg = NULL; - - GNUNET_free_non_null (allow_methods); - GNUNET_free (api); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Gns REST plugin is finished\n"); - return NULL; -} - -/* end of plugin_rest_gns.c */ - diff --git a/src/identity/Makefile.am b/src/identity/Makefile.am index e7104f0c3..1f21fc65d 100644 --- a/src/identity/Makefile.am +++ b/src/identity/Makefile.am @@ -39,14 +39,6 @@ bin_PROGRAMS = \ libexec_PROGRAMS = \ gnunet-service-identity -if HAVE_MHD -if HAVE_JSON -plugin_LTLIBRARIES = \ - libgnunet_plugin_rest_identity.la -endif -endif - - gnunet_service_identity_SOURCES = \ gnunet-service-identity.c gnunet_service_identity_LDADD = \ @@ -55,17 +47,6 @@ gnunet_service_identity_LDADD = \ $(GN_LIBINTL) -libgnunet_plugin_rest_identity_la_SOURCES = \ - plugin_rest_identity.c -libgnunet_plugin_rest_identity_la_LIBADD = \ - libgnunetidentity.la \ - $(top_builddir)/src/rest/libgnunetrest.la \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -ljansson -lmicrohttpd -libgnunet_plugin_rest_identity_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - - gnunet_identity_SOURCES = \ gnunet-identity.c gnunet_identity_LDADD = \ diff --git a/src/identity/plugin_rest_identity.c b/src/identity/plugin_rest_identity.c deleted file mode 100644 index 9f1765a63..000000000 --- a/src/identity/plugin_rest_identity.c +++ /dev/null @@ -1,1319 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -/** - * @author Martin Schanzenbach - * @author Philippe Buschmann - * @file identity/plugin_rest_identity.c - * @brief GNUnet Identity REST plugin - */ - -#include "platform.h" -#include "gnunet_rest_plugin.h" -#include "gnunet_identity_service.h" -#include "gnunet_rest_lib.h" -#include "microhttpd.h" -#include - -/** - * Identity Namespace - */ -#define GNUNET_REST_API_NS_IDENTITY "/identity" - -/** - * Identity Namespace with public key specifier - */ -#define GNUNET_REST_API_NS_IDENTITY_ALL "/identity/all" - -/** - * Identity Namespace with public key specifier - */ -#define GNUNET_REST_API_NS_IDENTITY_PUBKEY "/identity/pubkey" - -/** - * Identity Namespace with public key specifier - */ -#define GNUNET_REST_API_NS_IDENTITY_NAME "/identity/name" - -/** - * Identity Subsystem Namespace - */ -#define GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM "/identity/subsystem" - -/** - * Parameter public key - */ -#define GNUNET_REST_IDENTITY_PARAM_PUBKEY "pubkey" - -/** - * Parameter subsystem - */ -#define GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM "subsystem" - -/** - * Parameter name - */ -#define GNUNET_REST_IDENTITY_PARAM_NAME "name" - -/** - * Parameter new name - */ -#define GNUNET_REST_IDENTITY_PARAM_NEWNAME "newname" - -/** - * Error message Unknown Error - */ -#define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error" - -/** - * Error message No identity found - */ -#define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found" - -/** - * Error message Missing identity name - */ -#define GNUNET_REST_IDENTITY_MISSING_NAME "Missing identity name" - -/** - * Error message Missing identity name - */ -#define GNUNET_REST_IDENTITY_MISSING_PUBKEY "Missing identity public key" - -/** - * Error message No data - */ -#define GNUNET_REST_ERROR_NO_DATA "No data" - -/** - * Error message Data invalid - */ -#define GNUNET_REST_ERROR_DATA_INVALID "Data invalid" - -/** - * State while collecting all egos - */ -#define ID_REST_STATE_INIT 0 - -/** - * Done collecting egos - */ -#define ID_REST_STATE_POST_INIT 1 - -/** - * The configuration handle - */ -const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * HTTP methods allows for this plugin - */ -static char* allow_methods; - -/** - * @brief struct returned by the initialization function of the plugin - */ -struct Plugin -{ - const struct GNUNET_CONFIGURATION_Handle *cfg; -}; - -/** - * The ego list - */ -struct EgoEntry -{ - /** - * DLL - */ - struct EgoEntry *next; - - /** - * DLL - */ - struct EgoEntry *prev; - - /** - * Ego Identifier - */ - char *identifier; - - /** - * Public key string - */ - char *keystring; - - /** - * The Ego - */ - struct GNUNET_IDENTITY_Ego *ego; -}; - -/** - * The request handle - */ -struct RequestHandle -{ - /** - * The data from the REST request - */ - const char* data; - - /** - * The name to look up - */ - char *name; - - /** - * the length of the REST data - */ - size_t data_size; - - - /** - * Ego list - */ - struct EgoEntry *ego_head; - - /** - * Ego list - */ - struct EgoEntry *ego_tail; - - /** - * The processing state - */ - int state; - - /** - * Handle to Identity service. - */ - struct GNUNET_IDENTITY_Handle *identity_handle; - - /** - * IDENTITY Operation - */ - struct GNUNET_IDENTITY_Operation *op; - - /** - * Rest connection - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * Desired timeout for the lookup (default is no timeout). - */ - struct GNUNET_TIME_Relative timeout; - - /** - * ID of a task associated with the resolution process. - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * The url - */ - char *url; - - /** - * Error response message - */ - char *emsg; - - /** - * Response code - */ - int response_code; - -}; - -/** - * Cleanup lookup handle - * @param handle Handle to clean up - */ -static void -cleanup_handle (void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct EgoEntry *ego_tmp; - - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); - if (NULL != handle->timeout_task) - { - GNUNET_SCHEDULER_cancel (handle->timeout_task); - handle->timeout_task = NULL; - } - - if (NULL != handle->url) - GNUNET_free(handle->url); - if (NULL != handle->emsg) - GNUNET_free(handle->emsg); - if (NULL != handle->name) - GNUNET_free (handle->name); - if (NULL != handle->identity_handle) - GNUNET_IDENTITY_disconnect (handle->identity_handle); - - for (ego_entry = handle->ego_head; - NULL != ego_entry;) - { - ego_tmp = ego_entry; - ego_entry = ego_entry->next; - GNUNET_free(ego_tmp->identifier); - GNUNET_free(ego_tmp->keystring); - GNUNET_free(ego_tmp); - } - - GNUNET_free(handle); -} - -/** - * Task run on errors. Reports an error and cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - json_t *json_error = json_object(); - char *response; - - if (NULL == handle->emsg) - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_ERROR_UNKNOWN); - - json_object_set_new(json_error,"error", json_string(handle->emsg)); - - if (0 == handle->response_code) - handle->response_code = MHD_HTTP_OK; - response = json_dumps (json_error, 0); - resp = GNUNET_REST_create_response (response); - handle->proc (handle->proc_cls, resp, handle->response_code); - json_decref(json_error); - GNUNET_free(response); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - - -/** - * Get EgoEntry from list with either a public key or a name - * If public key and name are not NULL, it returns the public key result first - * - * @param handle the RequestHandle - * @param pubkey the public key of an identity (only one can be NULL) - * @param name the name of an identity (only one can be NULL) - * @return EgoEntry or NULL if not found - */ -struct EgoEntry* -get_egoentry(struct RequestHandle *handle, char* pubkey, char *name) -{ - struct EgoEntry *ego_entry; - if (NULL != pubkey) - { - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (0 != strcasecmp (pubkey, ego_entry->keystring)) - continue; - return ego_entry; - } - } - if (NULL != name) - { - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (0 != strcasecmp (name, ego_entry->identifier)) - continue; - return ego_entry; - } - } - return NULL; -} - - -/** - * Callback for GET Request with subsystem - * - * @param cls the RequestHandle - * @param ego the Ego found - * @param ctx the context - * @param name the id of the ego - */ -static void -ego_get_for_subsystem (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *name) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - struct GNUNET_CRYPTO_EcdsaPublicKey public_key; - json_t *json_root; - char *result_str; - char *public_key_string; - - if(NULL == ego) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - GNUNET_IDENTITY_ego_get_public_key(ego,&public_key); - public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string(&public_key); - - // create json with subsystem identity - json_root = json_object (); - json_object_set_new (json_root, - GNUNET_REST_IDENTITY_PARAM_PUBKEY, - json_string(public_key_string)); - json_object_set_new (json_root, - GNUNET_REST_IDENTITY_PARAM_NAME, - json_string(name)); - - result_str = json_dumps (json_root, 0); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - - json_decref (json_root); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free(result_str); - GNUNET_free(public_key_string); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - -/** - * Handle identity GET request for subsystem - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_get_subsystem (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - char *subsystem; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url)) - { - handle->emsg = GNUNET_strdup("Missing subsystem name"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - subsystem = &handle->url[strlen ( - GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) + 1]; - //requested default identity of subsystem - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsystem); - - handle->op = GNUNET_IDENTITY_get (handle->identity_handle, - subsystem, - &ego_get_for_subsystem, - handle); - - if (NULL == handle->op) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } -} - - -/** - * Handle identity GET request - responds with all identities - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_get_all (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct MHD_Response *resp; - json_t *json_root; - json_t *json_ego; - char *result_str; - - json_root = json_array (); - //Return ego/egos - for (ego_entry = handle->ego_head; - NULL != ego_entry; ego_entry = ego_entry->next) - { - json_ego = json_object (); - json_object_set_new (json_ego, - GNUNET_REST_IDENTITY_PARAM_PUBKEY, - json_string (ego_entry->keystring)); - json_object_set_new (json_ego, - GNUNET_REST_IDENTITY_PARAM_NAME, - json_string (ego_entry->identifier)); - json_array_append (json_root, json_ego); - json_decref (json_ego); - } - - if ((size_t) 0 == json_array_size (json_root)) - { - json_decref (json_root); - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - result_str = json_dumps (json_root, 0); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - - json_decref (json_root); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free(result_str); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Responds with the ego_entry identity - * - * @param handle the struct RequestHandle - * @param ego_entry the struct EgoEntry for the response - */ -void -ego_get_response (struct RequestHandle *handle, struct EgoEntry *ego_entry) -{ - struct MHD_Response *resp; - json_t *json_ego; - char *result_str; - - json_ego = json_object (); - json_object_set_new (json_ego, - GNUNET_REST_IDENTITY_PARAM_PUBKEY, - json_string (ego_entry->keystring)); - json_object_set_new (json_ego, - GNUNET_REST_IDENTITY_PARAM_NAME, - json_string (ego_entry->identifier)); - - result_str = json_dumps (json_ego, 0); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - - json_decref (json_ego); - GNUNET_free(result_str); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Handle identity GET request with a public key - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *keystring; - - keystring = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1]; - ego_entry = get_egoentry(handle, keystring, NULL); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - ego_get_response(handle, ego_entry); -} - -/** - * Handle identity GET request with a name - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_get_name (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *egoname; - - egoname = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - egoname = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1]; - ego_entry = get_egoentry(handle, NULL, egoname); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - ego_get_response(handle, ego_entry); -} - - -/** - * Processing finished - * - * @param cls request handle - * @param emsg error message - */ -static void -do_finished (void *cls, const char *emsg) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - handle->op = NULL; - if (NULL != emsg) - { - handle->emsg = GNUNET_strdup(emsg); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (0 == handle->response_code) - { - handle->response_code = MHD_HTTP_NO_CONTENT; - } - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, handle->response_code); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Processing edit ego with EgoEntry ego_entry - * - * @param handle the struct RequestHandle - * @param ego_entry the struct EgoEntry we want to edit - */ -void -ego_edit (struct RequestHandle *handle, struct EgoEntry *ego_entry) -{ - struct EgoEntry *ego_entry_tmp; - struct MHD_Response *resp; - json_t *data_js; - json_error_t err; - char *newname; - char term_data[handle->data_size + 1]; - int json_state; - - //if no data - if (0 >= handle->data_size) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - //if not json - term_data[handle->data_size] = '\0'; - GNUNET_memcpy(term_data, handle->data, handle->data_size); - data_js = json_loads (term_data,JSON_DECODE_ANY,&err); - - if (NULL == data_js) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - newname = NULL; - //NEW NAME - json_state = 0; - json_state = json_unpack(data_js, - "{s:s!}", - GNUNET_REST_IDENTITY_PARAM_NEWNAME, - &newname); - //Change name with pubkey or name identifier - if (0 != json_state) - { - - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - if (NULL == newname) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - if (0 >= strlen (newname)) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - ego_entry_tmp = get_egoentry (handle, NULL, newname); - if (NULL != ego_entry_tmp) - { - //Ego with same name not allowed (even if its the ego we change) - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); - json_decref (data_js); - return; - } - handle->op = GNUNET_IDENTITY_rename (handle->identity_handle, - ego_entry->identifier, - newname, - &do_finished, - handle); - if (NULL == handle->op) - { - handle->emsg = GNUNET_strdup("Rename failed"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - json_decref (data_js); - return; - -} - - -/** - * Handle identity PUT request with public key - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_edit_pubkey (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *keystring; - - keystring = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1]; - ego_entry = get_egoentry(handle, keystring, NULL); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - ego_edit(handle,ego_entry); -} - -/** - * Handle identity PUT request with name - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *name; - - name = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1]; - ego_entry = get_egoentry(handle, NULL, name); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - ego_edit(handle,ego_entry); -} - -/** - * Handle identity subsystem PUT request with name - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_edit_subsystem (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - json_t *data_js; - json_error_t err; - char *newsubsys; - char *name; - char term_data[handle->data_size + 1]; - int json_state; - - name = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM)+1]; - ego_entry = get_egoentry(handle, NULL, name); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - //if no data - if (0 >= handle->data_size) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - //if not json - term_data[handle->data_size] = '\0'; - GNUNET_memcpy(term_data, handle->data, handle->data_size); - data_js = json_loads (term_data,JSON_DECODE_ANY,&err); - - if (NULL == data_js) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - newsubsys = NULL; - //SUBSYSTEM - json_state = 0; - json_state = json_unpack(data_js, - "{s:s!}", - GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM, - &newsubsys); - //Change subsystem with pubkey or name identifier - if (0 != json_state) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - if (NULL == newsubsys) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - if (0 >= strlen (newsubsys)) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - handle->response_code = MHD_HTTP_NO_CONTENT; - handle->op = GNUNET_IDENTITY_set (handle->identity_handle, - newsubsys, - ego_entry->ego, - &do_finished, - handle); - if (NULL == handle->op) - { - handle->emsg = GNUNET_strdup("Setting subsystem failed"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - json_decref (data_js); - return; - -} - -/** - * Handle identity POST request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_create (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct MHD_Response *resp; - json_t *data_js; - json_error_t err; - char* egoname; - int json_unpack_state; - char term_data[handle->data_size + 1]; - - if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url)) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - if (0 >= handle->data_size) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - term_data[handle->data_size] = '\0'; - GNUNET_memcpy(term_data, handle->data, handle->data_size); - data_js = json_loads (term_data, - JSON_DECODE_ANY, - &err); - if (NULL == data_js) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - json_unpack_state = 0; - json_unpack_state = json_unpack(data_js, - "{s:s!}", - GNUNET_REST_IDENTITY_PARAM_NAME, - &egoname); - if (0 != json_unpack_state) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - if (NULL == egoname) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - if (0 >= strlen (egoname)) - { - json_decref (data_js); - handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - GNUNET_STRINGS_utf8_tolower(egoname, egoname); - for (ego_entry = handle->ego_head; - NULL != ego_entry; ego_entry = ego_entry->next) - { - if (0 == strcasecmp (egoname, ego_entry->identifier)) - { - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); - json_decref (data_js); - return; - } - } - handle->name = GNUNET_strdup(egoname); - json_decref (data_js); - handle->response_code = MHD_HTTP_CREATED; - handle->op = GNUNET_IDENTITY_create (handle->identity_handle, handle->name, - &do_finished, handle); -} - -/** - * Handle identity DELETE request with public key - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *keystring; - - keystring = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1]; - ego_entry = get_egoentry(handle, keystring, NULL); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - handle->response_code = MHD_HTTP_NO_CONTENT; - handle->op = GNUNET_IDENTITY_delete (handle->identity_handle, - ego_entry->identifier, - &do_finished, - handle); -} - - -/** - * Handle identity DELETE request with name - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *name; - - name = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1]; - ego_entry = get_egoentry(handle, NULL, name); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - handle->response_code = MHD_HTTP_NO_CONTENT; - handle->op = GNUNET_IDENTITY_delete (handle->identity_handle, - ego_entry->identifier, - &do_finished, - handle); -} - - -/** - * Respond to OPTIONS request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -options_cont (struct GNUNET_REST_RequestHandle *con_handle, const char* url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - //For now, independent of path return all options - resp = GNUNET_REST_create_response (NULL); - MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); - return; -} - -/** - * Handle rest request - * - * @param handle the request handle - */ -static void -init_cont (struct RequestHandle *handle) -{ - struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = { - { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ALL, &ego_get_all }, - { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_get_pubkey }, - { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_get_name }, - { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_get_subsystem }, - { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_edit_pubkey }, - { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_edit_name }, - { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_edit_subsystem }, - { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create }, - { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_delete_pubkey }, - { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_delete_name }, - { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont }, - GNUNET_REST_HANDLER_END - }; - - if (GNUNET_NO - == GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, - handle)) - { - handle->response_code = err.error_code; - GNUNET_SCHEDULER_add_now (&do_error, handle); - } -} - -/** - * If listing is enabled, prints information about the egos. - * - * This function is initially called for all egos and then again - * whenever a ego's identifier changes or if it is deleted. At the - * end of the initial pass over all egos, the function is once called - * with 'NULL' for 'ego'. That does NOT mean that the callback won't - * be invoked in the future or that there was an error. - * - * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', - * this function is only called ONCE, and 'NULL' being passed in - * 'ego' does indicate an error (i.e. name is taken or no default - * value is known). If 'ego' is non-NULL and if '*ctx' - * is set in those callbacks, the value WILL be passed to a subsequent - * call to the identity callback of 'GNUNET_IDENTITY_connect' (if - * that one was not NULL). - * - * When an identity is renamed, this function is called with the - * (known) ego but the NEW identifier. - * - * When an identity is deleted, this function is called with the - * (known) ego and "NULL" for the 'identifier'. In this case, - * the 'ego' is henceforth invalid (and the 'ctx' should also be - * cleaned up). - * - * @param cls closure - * @param ego ego handle - * @param ctx context for application to store data for this ego - * (during the lifetime of this process, initially NULL) - * @param identifier identifier assigned by the user for this ego, - * NULL if the user just deleted the ego and it - * must thus no longer be used - */ -static void -init_egos (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx, - const char *identifier) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct GNUNET_CRYPTO_EcdsaPublicKey pk; - - if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state)) - { - handle->state = ID_REST_STATE_POST_INIT; - init_cont (handle); - return; - } - if (ID_REST_STATE_INIT == handle->state) - { - ego_entry = GNUNET_new(struct EgoEntry); - GNUNET_IDENTITY_ego_get_public_key (ego, &pk); - ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); - ego_entry->ego = ego; - GNUNET_asprintf (&ego_entry->identifier, "%s", identifier); - GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail, - ego_entry); - } -} - -/** - * Function processing the REST call - * - * @param method HTTP method - * @param url URL of the HTTP request - * @param data body of the HTTP request (optional) - * @param data_size length of the body - * @param proc callback function for the result - * @param proc_cls closure for callback function - * @return GNUNET_OK if request accepted - */ -static void -rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, void *proc_cls) -{ - struct RequestHandle *handle = GNUNET_new(struct RequestHandle); - - handle->response_code = 0; - handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; - handle->proc_cls = proc_cls; - handle->proc = proc; - handle->rest_handle = rest_handle; - handle->data = rest_handle->data; - handle->data_size = rest_handle->data_size; - - handle->url = GNUNET_strdup(rest_handle->url); - if (handle->url[strlen (handle->url) - 1] == '/') - handle->url[strlen (handle->url) - 1] = '\0'; - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); - - handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &init_egos, handle); - - handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout, - &do_error, handle); - - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); -} - -/** - * Entry point for the plugin. - * - * @param cls Config info - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_rest_identity_init (void *cls) -{ - static struct Plugin plugin; - struct GNUNET_REST_Plugin *api; - - cfg = cls; - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof(struct Plugin)); - plugin.cfg = cfg; - api = GNUNET_new(struct GNUNET_REST_Plugin); - api->cls = &plugin; - api->name = GNUNET_REST_API_NS_IDENTITY; - api->process_request = &rest_process_request; - GNUNET_asprintf (&allow_methods, "%s, %s, %s, %s, %s", - MHD_HTTP_METHOD_GET, - MHD_HTTP_METHOD_POST, - MHD_HTTP_METHOD_PUT, - MHD_HTTP_METHOD_DELETE, - MHD_HTTP_METHOD_OPTIONS); - - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Identity REST API initialized\n")); - return api; -} - -/** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ -void * -libgnunet_plugin_rest_identity_done (void *cls) -{ - struct GNUNET_REST_Plugin *api = cls; - struct Plugin *plugin = api->cls; - plugin->cfg = NULL; - - GNUNET_free_non_null(allow_methods); - GNUNET_free(api); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n"); - return NULL; -} - -/* end of plugin_rest_identity.c */ - diff --git a/src/jsonapi/Makefile.am b/src/jsonapi/Makefile.am index 054d3c550..0c6d60b10 100644 --- a/src/jsonapi/Makefile.am +++ b/src/jsonapi/Makefile.am @@ -8,7 +8,23 @@ endif lib_LTLIBRARIES = \ libgnunetjsonapi.la \ - libgnunetjsonapiutils.la + libgnunetjsonapiutils.la \ + libgnunet_plugin_rest_reclaim.la + +libgnunet_plugin_rest_reclaim_la_SOURCES = \ + plugin_rest_reclaim.c +libgnunet_plugin_rest_reclaim_la_LIBADD = \ + $(top_builddir)/src/identity/libgnunetidentity.la \ + $(top_builddir)/src/reclaim/libgnunetreclaim.la \ + $(top_builddir)/src/rest/libgnunetrest.la \ + libgnunetjsonapi.la \ + $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ + $(LTLIBINTL) -ljansson -lmicrohttpd +libgnunet_plugin_rest_reclaim_la_LDFLAGS = \ + i$(GN_PLUGIN_LDFLAGS) + libgnunetjsonapiutils_la_LDFLAGS = \ -version-info 0:0:0 \ diff --git a/src/jsonapi/plugin_rest_reclaim.c b/src/jsonapi/plugin_rest_reclaim.c new file mode 100644 index 000000000..38ffc4ddb --- /dev/null +++ b/src/jsonapi/plugin_rest_reclaim.c @@ -0,0 +1,1253 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +/** + * @author Martin Schanzenbach + * @author Philippe Buschmann + * @file reclaim/plugin_rest_reclaim.c + * @brief GNUnet reclaim REST plugin + * + */ + +#include "platform.h" +#include "gnunet_rest_plugin.h" +#include "gnunet_identity_service.h" +#include "gnunet_gns_service.h" +#include "gnunet_gnsrecord_lib.h" +#include "gnunet_namestore_service.h" +#include "gnunet_rest_lib.h" +#include "gnunet_jsonapi_lib.h" +#include "gnunet_jsonapi_util.h" +#include "microhttpd.h" +#include +#include +#include "gnunet_signatures.h" +#include "gnunet_reclaim_attribute_lib.h" +#include "gnunet_reclaim_service.h" + +/** + * REST root namespace + */ +#define GNUNET_REST_API_NS_RECLAIM "/reclaim" + +/** + * Attribute namespace + */ +#define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/reclaim/attributes" + +/** + * Ticket namespace + */ +#define GNUNET_REST_API_NS_IDENTITY_TICKETS "/reclaim/tickets" + +/** + * Revoke namespace + */ +#define GNUNET_REST_API_NS_IDENTITY_REVOKE "/reclaim/revoke" + +/** + * Revoke namespace + */ +#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/reclaim/consume" + +/** + * Attribute key + */ +#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE "attribute" + +/** + * Ticket key + */ +#define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket" + + +/** + * Value key + */ +#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE_VALUE "value" + +/** + * State while collecting all egos + */ +#define ID_REST_STATE_INIT 0 + +/** + * Done collecting egos + */ +#define ID_REST_STATE_POST_INIT 1 + +/** + * The configuration handle + */ +const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * HTTP methods allows for this plugin + */ +static char* allow_methods; + +/** + * @brief struct returned by the initialization function of the plugin + */ +struct Plugin +{ + const struct GNUNET_CONFIGURATION_Handle *cfg; +}; + +/** + * The ego list + */ +struct EgoEntry +{ + /** + * DLL + */ + struct EgoEntry *next; + + /** + * DLL + */ + struct EgoEntry *prev; + + /** + * Ego Identifier + */ + char *identifier; + + /** + * Public key string + */ + char *keystring; + + /** + * The Ego + */ + struct GNUNET_IDENTITY_Ego *ego; +}; + + +struct RequestHandle +{ + /** + * Ego list + */ + struct EgoEntry *ego_head; + + /** + * Ego list + */ + struct EgoEntry *ego_tail; + + /** + * Selected ego + */ + struct EgoEntry *ego_entry; + + /** + * Pointer to ego private key + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; + + /** + * The processing state + */ + int state; + + /** + * Handle to Identity service. + */ + struct GNUNET_IDENTITY_Handle *identity_handle; + + /** + * Rest connection + */ + struct GNUNET_REST_RequestHandle *rest_handle; + + /** + * Handle to NAMESTORE + */ + struct GNUNET_NAMESTORE_Handle *namestore_handle; + + /** + * Iterator for NAMESTORE + */ + struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it; + + /** + * Attribute claim list + */ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list; + + /** + * IDENTITY Operation + */ + struct GNUNET_IDENTITY_Operation *op; + + /** + * Identity Provider + */ + struct GNUNET_RECLAIM_Handle *idp; + + /** + * Idp Operation + */ + struct GNUNET_RECLAIM_Operation *idp_op; + + /** + * Attribute iterator + */ + struct GNUNET_RECLAIM_AttributeIterator *attr_it; + + /** + * Ticket iterator + */ + struct GNUNET_RECLAIM_TicketIterator *ticket_it; + + /** + * A ticket + */ + struct GNUNET_RECLAIM_Ticket ticket; + + /** + * Desired timeout for the lookup (default is no timeout). + */ + struct GNUNET_TIME_Relative timeout; + + /** + * ID of a task associated with the resolution process. + */ + struct GNUNET_SCHEDULER_Task *timeout_task; + + /** + * The plugin result processor + */ + GNUNET_REST_ResultProcessor proc; + + /** + * The closure of the result processor + */ + void *proc_cls; + + /** + * The url + */ + char *url; + + /** + * Error response message + */ + char *emsg; + + /** + * Reponse code + */ + int response_code; + + /** + * Response object + */ + struct GNUNET_JSONAPI_Document *resp_object; + +}; + +/** + * Cleanup lookup handle + * @param handle Handle to clean up + */ +static void +cleanup_handle (struct RequestHandle *handle) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp; + struct EgoEntry *ego_entry; + struct EgoEntry *ego_tmp; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up\n"); + if (NULL != handle->resp_object) + GNUNET_JSONAPI_document_delete (handle->resp_object); + if (NULL != handle->timeout_task) + GNUNET_SCHEDULER_cancel (handle->timeout_task); + if (NULL != handle->identity_handle) + GNUNET_IDENTITY_disconnect (handle->identity_handle); + if (NULL != handle->attr_it) + GNUNET_RECLAIM_get_attributes_stop (handle->attr_it); + if (NULL != handle->ticket_it) + GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it); + if (NULL != handle->idp) + GNUNET_RECLAIM_disconnect (handle->idp); + if (NULL != handle->url) + GNUNET_free (handle->url); + if (NULL != handle->emsg) + GNUNET_free (handle->emsg); + if (NULL != handle->namestore_handle) + GNUNET_NAMESTORE_disconnect (handle->namestore_handle); + if ( NULL != handle->attr_list ) + { + for (claim_entry = handle->attr_list->list_head; + NULL != claim_entry;) + { + claim_tmp = claim_entry; + claim_entry = claim_entry->next; + GNUNET_free(claim_tmp->claim); + GNUNET_free(claim_tmp); + } + GNUNET_free (handle->attr_list); + } + for (ego_entry = handle->ego_head; + NULL != ego_entry;) + { + ego_tmp = ego_entry; + ego_entry = ego_entry->next; + GNUNET_free (ego_tmp->identifier); + GNUNET_free (ego_tmp->keystring); + GNUNET_free (ego_tmp); + } + if (NULL != handle->attr_it) + { + GNUNET_free(handle->attr_it); + } + GNUNET_free (handle); +} + +static void +cleanup_handle_delayed (void *cls) +{ + cleanup_handle (cls); +} + + +/** + * Task run on error, sends error message. Cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_error (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + char *json_error; + + GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", + handle->emsg); + if ( 0 == handle->response_code ) + { + handle->response_code = MHD_HTTP_BAD_REQUEST; + } + resp = GNUNET_REST_create_response (json_error); + MHD_add_response_header (resp, "Content-Type", "application/json"); + handle->proc (handle->proc_cls, resp, handle->response_code); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); + GNUNET_free (json_error); +} + + +/** + * Task run on timeout, sends error message. Cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_timeout (void *cls) +{ + struct RequestHandle *handle = cls; + + handle->timeout_task = NULL; + do_error (handle); +} + + +static void +collect_error_cb (void *cls) +{ + struct RequestHandle *handle = cls; + + do_error (handle); +} + +static void +finished_cont (void *cls, + int32_t success, + const char *emsg) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + + resp = GNUNET_REST_create_response (emsg); + if (GNUNET_OK != success) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); +} + + +/** + * Return attributes for identity + * + * @param cls the request handle + */ +static void +return_response (void *cls) +{ + char* result_str; + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + + GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); + resp = GNUNET_REST_create_response (result_str); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free (result_str); + cleanup_handle (handle); +} + +static void +collect_finished_cb (void *cls) +{ + struct RequestHandle *handle = cls; + //Done + handle->attr_it = NULL; + handle->ticket_it = NULL; + GNUNET_SCHEDULER_add_now (&return_response, handle); +} + + +/** + * Collect all attributes for an ego + * + */ +static void +ticket_collect (void *cls, + const struct GNUNET_RECLAIM_Ticket *ticket) +{ + struct GNUNET_JSONAPI_Resource *json_resource; + struct RequestHandle *handle = cls; + json_t *value; + char* tmp; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n"); + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, + sizeof (uint64_t)); + json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET, + tmp); + GNUNET_free (tmp); + GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); + + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + value = json_string (tmp); + GNUNET_JSONAPI_resource_add_attr (json_resource, + "issuer", + value); + GNUNET_free (tmp); + json_decref (value); + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + value = json_string (tmp); + GNUNET_JSONAPI_resource_add_attr (json_resource, + "audience", + value); + GNUNET_free (tmp); + json_decref (value); + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, + sizeof (uint64_t)); + value = json_string (tmp); + GNUNET_JSONAPI_resource_add_attr (json_resource, + "rnd", + value); + GNUNET_free (tmp); + json_decref (value); + GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it); +} + + + +/** + * List tickets for identity request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *identity; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n", + handle->url); + if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= + strlen (handle->url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1; + + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + handle->resp_object = GNUNET_JSONAPI_document_new (); + + if (NULL == ego_entry) + { + //Done + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", + identity); + GNUNET_SCHEDULER_add_now (&return_response, handle); + return; + } + priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->ticket_it = GNUNET_RECLAIM_ticket_iteration_start (handle->idp, + priv_key, + &collect_error_cb, + handle, + &ticket_collect, + handle, + &collect_finished_cb, + handle); +} + + +static void +add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; + const char* identity; + const char* name_str; + const char* value_str; + const char* exp_str; + + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct MHD_Response *resp; + struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute; + struct GNUNET_JSONAPI_Document *json_obj; + struct GNUNET_JSONAPI_Resource *json_res; + struct GNUNET_TIME_Relative exp; + char term_data[handle->rest_handle->data_size+1]; + json_t *value_json; + json_t *data_json; + json_t *exp_json; + json_error_t err; + struct GNUNET_JSON_Specification docspec[] = { + GNUNET_JSON_spec_jsonapi_document (&json_obj), + GNUNET_JSON_spec_end() + }; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n", + handle->url); + if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= + strlen (handle->url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1; + + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + + if (NULL == ego_entry) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Identity unknown (%s)\n", identity); + GNUNET_JSONAPI_document_delete (json_obj); + return; + } + identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + + if (0 >= handle->rest_handle->data_size) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, + JSON_DECODE_ANY, + &err); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (data_json, docspec, + NULL, NULL)); + json_decref (data_json); + if (NULL == json_obj) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse JSONAPI Object from %s\n", + term_data); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Cannot create more than 1 resource! (Got %d)\n", + GNUNET_JSONAPI_document_resource_count (json_obj)); + GNUNET_JSONAPI_document_delete (json_obj); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); + if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, + GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unsupported JSON data type\n"); + GNUNET_JSONAPI_document_delete (json_obj); + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); + cleanup_handle (handle); + return; + } + name_str = GNUNET_JSONAPI_resource_get_id (json_res); + exp_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "exp"); + exp_str = json_string_value (exp_json); + if (NULL == exp_str) { + exp = GNUNET_TIME_UNIT_HOURS; + } else { + if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (exp_str, + &exp)) { + exp = GNUNET_TIME_UNIT_HOURS; + } + } + + value_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "value"); + value_str = json_string_value (value_json); + attribute = GNUNET_RECLAIM_ATTRIBUTE_claim_new (name_str, + GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING, + value_str, + strlen (value_str) + 1); + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp, + identity_priv, + attribute, + &exp, + &finished_cont, + handle); + GNUNET_free (attribute); + GNUNET_JSONAPI_document_delete (json_obj); +} + + + +/** + * Collect all attributes for an ego + * + */ +static void +attr_collect (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) +{ + struct GNUNET_JSONAPI_Resource *json_resource; + struct RequestHandle *handle = cls; + json_t *value; + char* tmp_value; + + if ((NULL == attr->name) || (NULL == attr->data)) + { + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", + attr->name); + json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE, + attr->name); + GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); + + tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, + attr->data, + attr->data_size); + + value = json_string (tmp_value); + + GNUNET_JSONAPI_resource_add_attr (json_resource, + "value", + value); + json_decref (value); + GNUNET_free(tmp_value); + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); +} + + + +/** + * List attributes for identity request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *identity; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n", + handle->url); + if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= + strlen (handle->url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1; + + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + handle->resp_object = GNUNET_JSONAPI_document_new (); + + + if (NULL == ego_entry) + { + //Done + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", + identity); + GNUNET_SCHEDULER_add_now (&return_response, handle); + return; + } + priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp, + priv_key, + &collect_error_cb, + handle, + &attr_collect, + handle, + &collect_finished_cb, + handle); +} + + +static void +revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; + const char* identity_str; + const char* audience_str; + const char* rnd_str; + + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct MHD_Response *resp; + struct GNUNET_RECLAIM_Ticket ticket; + struct GNUNET_JSONAPI_Document *json_obj; + struct GNUNET_JSONAPI_Resource *json_res; + struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk; + char term_data[handle->rest_handle->data_size+1]; + json_t *rnd_json; + json_t *identity_json; + json_t *audience_json; + json_t *data_json; + json_error_t err; + struct GNUNET_JSON_Specification docspec[] = { + GNUNET_JSON_spec_jsonapi_document (&json_obj), + GNUNET_JSON_spec_end() + }; + + if (0 >= handle->rest_handle->data_size) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, + JSON_DECODE_ANY, + &err); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (data_json, docspec, + NULL, NULL)); + json_decref (data_json); + if (NULL == json_obj) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse JSONAPI Object from %s\n", + term_data); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Cannot create more than 1 resource! (Got %d)\n", + GNUNET_JSONAPI_document_resource_count (json_obj)); + GNUNET_JSONAPI_document_delete (json_obj); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); + if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, + GNUNET_REST_JSONAPI_IDENTITY_TICKET)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unsupported JSON data type\n"); + GNUNET_JSONAPI_document_delete (json_obj); + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); + cleanup_handle (handle); + return; + } + rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "rnd"); + identity_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "issuer"); + audience_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "audience"); + rnd_str = json_string_value (rnd_json); + identity_str = json_string_value (identity_json); + audience_str = json_string_value (audience_json); + + GNUNET_STRINGS_string_to_data (rnd_str, + strlen (rnd_str), + &ticket.rnd, + sizeof (uint64_t)); + GNUNET_STRINGS_string_to_data (identity_str, + strlen (identity_str), + &ticket.identity, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + GNUNET_STRINGS_string_to_data (audience_str, + strlen (audience_str), + &ticket.audience, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + { + GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, + &tmp_pk); + if (0 == memcmp (&ticket.identity, + &tmp_pk, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) + break; + } + if (NULL == ego_entry) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Identity unknown (%s)\n", identity_str); + GNUNET_JSONAPI_document_delete (json_obj); + return; + } + identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp, + identity_priv, + &ticket, + &finished_cont, + handle); + GNUNET_JSONAPI_document_delete (json_obj); +} + +static void +consume_cont (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) +{ + struct RequestHandle *handle = cls; + struct GNUNET_JSONAPI_Resource *json_resource; + json_t *value; + + if (NULL == identity) + { + GNUNET_SCHEDULER_add_now (&return_response, handle); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", + attr->name); + json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE, + attr->name); + GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); + + value = json_string (attr->data); + GNUNET_JSONAPI_resource_add_attr (json_resource, + "value", + value); + json_decref (value); +} + +static void +consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; + const char* identity_str; + const char* audience_str; + const char* rnd_str; + + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct MHD_Response *resp; + struct GNUNET_RECLAIM_Ticket ticket; + struct GNUNET_JSONAPI_Document *json_obj; + struct GNUNET_JSONAPI_Resource *json_res; + struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk; + char term_data[handle->rest_handle->data_size+1]; + json_t *rnd_json; + json_t *identity_json; + json_t *audience_json; + json_t *data_json; + json_error_t err; + struct GNUNET_JSON_Specification docspec[] = { + GNUNET_JSON_spec_jsonapi_document (&json_obj), + GNUNET_JSON_spec_end() + }; + + if (0 >= handle->rest_handle->data_size) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, + JSON_DECODE_ANY, + &err); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (data_json, docspec, + NULL, NULL)); + json_decref (data_json); + if (NULL == json_obj) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse JSONAPI Object from %s\n", + term_data); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Cannot create more than 1 resource! (Got %d)\n", + GNUNET_JSONAPI_document_resource_count (json_obj)); + GNUNET_JSONAPI_document_delete (json_obj); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); + if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, + GNUNET_REST_JSONAPI_IDENTITY_TICKET)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unsupported JSON data type\n"); + GNUNET_JSONAPI_document_delete (json_obj); + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); + cleanup_handle (handle); + return; + } + rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "rnd"); + identity_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "identity"); + audience_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "audience"); + rnd_str = json_string_value (rnd_json); + identity_str = json_string_value (identity_json); + audience_str = json_string_value (audience_json); + + GNUNET_STRINGS_string_to_data (rnd_str, + strlen (rnd_str), + &ticket.rnd, + sizeof (uint64_t)); + GNUNET_STRINGS_string_to_data (identity_str, + strlen (identity_str), + &ticket.identity, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + GNUNET_STRINGS_string_to_data (audience_str, + strlen (audience_str), + &ticket.audience, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + { + GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, + &tmp_pk); + if (0 == memcmp (&ticket.audience, + &tmp_pk, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) + break; + } + if (NULL == ego_entry) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Identity unknown (%s)\n", identity_str); + GNUNET_JSONAPI_document_delete (json_obj); + return; + } + identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->resp_object = GNUNET_JSONAPI_document_new (); + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp, + identity_priv, + &ticket, + &consume_cont, + handle); + GNUNET_JSONAPI_document_delete (json_obj); +} + + + +/** + * Respond to OPTIONS request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +options_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct MHD_Response *resp; + struct RequestHandle *handle = cls; + + //For now, independent of path return all options + resp = GNUNET_REST_create_response (NULL); + MHD_add_response_header (resp, + "Access-Control-Allow-Methods", + allow_methods); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + cleanup_handle (handle); + return; +} + +/** + * Handle rest request + * + * @param handle the request handle + */ +static void +init_cont (struct RequestHandle *handle) +{ + struct GNUNET_REST_RequestHandlerError err; + static const struct GNUNET_REST_RequestHandler handlers[] = { + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &list_attribute_cont}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &add_attribute_cont}, + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont}, + {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, + &options_cont}, + GNUNET_REST_HANDLER_END + }; + + if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, + handlers, + &err, + handle)) + { + handle->response_code = err.error_code; + GNUNET_SCHEDULER_add_now (&do_error, handle); + } +} + +/** + * If listing is enabled, prints information about the egos. + * + * This function is initially called for all egos and then again + * whenever a ego's identifier changes or if it is deleted. At the + * end of the initial pass over all egos, the function is once called + * with 'NULL' for 'ego'. That does NOT mean that the callback won't + * be invoked in the future or that there was an error. + * + * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', + * this function is only called ONCE, and 'NULL' being passed in + * 'ego' does indicate an error (i.e. name is taken or no default + * value is known). If 'ego' is non-NULL and if '*ctx' + * is set in those callbacks, the value WILL be passed to a subsequent + * call to the identity callback of 'GNUNET_IDENTITY_connect' (if + * that one was not NULL). + * + * When an identity is renamed, this function is called with the + * (known) ego but the NEW identifier. + * + * When an identity is deleted, this function is called with the + * (known) ego and "NULL" for the 'identifier'. In this case, + * the 'ego' is henceforth invalid (and the 'ctx' should also be + * cleaned up). + * + * @param cls closure + * @param ego ego handle + * @param ctx context for application to store data for this ego + * (during the lifetime of this process, initially NULL) + * @param identifier identifier assigned by the user for this ego, + * NULL if the user just deleted the ego and it + * must thus no longer be used + */ +static void +list_ego (void *cls, + struct GNUNET_IDENTITY_Ego *ego, + void **ctx, + const char *identifier) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct GNUNET_CRYPTO_EcdsaPublicKey pk; + + if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state)) + { + handle->state = ID_REST_STATE_POST_INIT; + init_cont (handle); + return; + } + if (ID_REST_STATE_INIT == handle->state) { + ego_entry = GNUNET_new (struct EgoEntry); + GNUNET_IDENTITY_ego_get_public_key (ego, &pk); + ego_entry->keystring = + GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); + ego_entry->ego = ego; + ego_entry->identifier = GNUNET_strdup (identifier); + GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); + } + +} + +static void +rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, + GNUNET_REST_ResultProcessor proc, + void *proc_cls) +{ + struct RequestHandle *handle = GNUNET_new (struct RequestHandle); + handle->response_code = 0; + handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; + handle->proc_cls = proc_cls; + handle->proc = proc; + handle->state = ID_REST_STATE_INIT; + handle->rest_handle = rest_handle; + + handle->url = GNUNET_strdup (rest_handle->url); + if (handle->url[strlen (handle->url)-1] == '/') + handle->url[strlen (handle->url)-1] = '\0'; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connecting...\n"); + handle->identity_handle = GNUNET_IDENTITY_connect (cfg, + &list_ego, + handle); + handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg); + handle->timeout_task = + GNUNET_SCHEDULER_add_delayed (handle->timeout, + &do_timeout, + handle); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connected\n"); +} + +/** + * Entry point for the plugin. + * + * @param cls Config info + * @return NULL on error, otherwise the plugin context + */ +void * +libgnunet_plugin_rest_reclaim_init (void *cls) +{ + static struct Plugin plugin; + struct GNUNET_REST_Plugin *api; + + cfg = cls; + if (NULL != plugin.cfg) + return NULL; /* can only initialize once! */ + memset (&plugin, 0, sizeof (struct Plugin)); + plugin.cfg = cfg; + api = GNUNET_new (struct GNUNET_REST_Plugin); + api->cls = &plugin; + api->name = GNUNET_REST_API_NS_RECLAIM; + api->process_request = &rest_identity_process_request; + GNUNET_asprintf (&allow_methods, + "%s, %s, %s, %s, %s", + MHD_HTTP_METHOD_GET, + MHD_HTTP_METHOD_POST, + MHD_HTTP_METHOD_PUT, + MHD_HTTP_METHOD_DELETE, + MHD_HTTP_METHOD_OPTIONS); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Identity Provider REST API initialized\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the plugin context (as returned by "init") + * @return always NULL + */ +void * +libgnunet_plugin_rest_reclaim_done (void *cls) +{ + struct GNUNET_REST_Plugin *api = cls; + struct Plugin *plugin = api->cls; + plugin->cfg = NULL; + + GNUNET_free_non_null (allow_methods); + GNUNET_free (api); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Identity Provider REST plugin is finished\n"); + return NULL; +} + +/* end of plugin_rest_reclaim.c */ diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am index 7f44c2a71..a349921d7 100644 --- a/src/namestore/Makefile.am +++ b/src/namestore/Makefile.am @@ -97,12 +97,6 @@ check_PROGRAMS = \ $(FLAT_TESTS) endif -if HAVE_MHD -if HAVE_JSON -REST_PLUGIN=libgnunet_plugin_rest_namestore.la -endif -endif - if ENABLE_TEST_RUN AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; TESTS = \ @@ -186,8 +180,7 @@ gnunet_service_namestore_LDADD = \ plugin_LTLIBRARIES = \ $(SQLITE_PLUGIN) \ $(POSTGRES_PLUGIN) \ - $(FLAT_PLUGIN) \ - $(REST_PLUGIN) + $(FLAT_PLUGIN) @@ -224,20 +217,6 @@ libgnunet_plugin_namestore_postgres_la_LIBADD = \ libgnunet_plugin_namestore_postgres_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) $(POSTGRESQL_LDFLAGS) -libgnunet_plugin_rest_namestore_la_SOURCES = \ - plugin_rest_namestore.c -libgnunet_plugin_rest_namestore_la_LIBADD = \ - libgnunetnamestore.la \ - $(top_builddir)/src/rest/libgnunetrest.la \ - $(top_builddir)/src/identity/libgnunetidentity.la \ - $(top_builddir)/src/json/libgnunetjson.la \ - $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -ljansson -lmicrohttpd -libgnunet_plugin_rest_namestore_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - - test_namestore_api_store_flat_SOURCES = \ test_namestore_api_store.c test_namestore_api_store_flat_LDADD = \ diff --git a/src/namestore/plugin_rest_namestore.c b/src/namestore/plugin_rest_namestore.c deleted file mode 100644 index 1d72d13ff..000000000 --- a/src/namestore/plugin_rest_namestore.c +++ /dev/null @@ -1,1004 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -/** - * @author Martin Schanzenbach - * @author Philippe Buschmann - * @file namestore/plugin_rest_namestore.c - * @brief GNUnet Namestore REST plugin - */ - -#include "platform.h" -#include "gnunet_rest_plugin.h" -#include "gnunet_gns_service.h" -#include "gnunet_namestore_service.h" -#include "gnunet_identity_service.h" -#include "gnunet_rest_lib.h" -#include "gnunet_json_lib.h" -#include "microhttpd.h" -#include - -/** - * Namestore Namespace - */ -#define GNUNET_REST_API_NS_NAMESTORE "/namestore" - -/** - * Error message Unknown Error - */ -#define GNUNET_REST_NAMESTORE_ERROR_UNKNOWN "Unknown Error" - -/** - * Error message No identity found - */ -#define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found" - -/** - * Error message No default zone specified - */ -#define GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE "No default zone specified" - -/** - * Error message Failed request - */ -#define GNUNET_REST_NAMESTORE_FAILED "Namestore action failed" - -/** - * Error message invalid data - */ -#define GNUNET_REST_NAMESTORE_INVALID_DATA "Data invalid" - -/** - * Error message No data - */ -#define GNUNET_REST_NAMESTORE_NO_DATA "No data" - -/** - * State while collecting all egos - */ -#define ID_REST_STATE_INIT 0 - -/** - * Done collecting egos - */ -#define ID_REST_STATE_POST_INIT 1 -/** - * The configuration handle - */ -const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * HTTP methods allows for this plugin - */ -static char* allow_methods; - -/** - * @brief struct returned by the initialization function of the plugin - */ -struct Plugin -{ - const struct GNUNET_CONFIGURATION_Handle *cfg; -}; - -/** - * The default namestore ego - */ -struct EgoEntry -{ - /** - * DLL - */ - struct EgoEntry *next; - - /** - * DLL - */ - struct EgoEntry *prev; - - /** - * Ego Identifier - */ - char *identifier; - - /** - * Public key string - */ - char *keystring; - - /** - * The Ego - */ - struct GNUNET_IDENTITY_Ego *ego; -}; - -/** - * The request handle - */ -struct RequestHandle -{ - /** - * Records to store - */ - char *record_name; - - /** - * Records to store - */ - struct GNUNET_GNSRECORD_Data *rd; - - /** - * NAMESTORE Operation - */ - struct GNUNET_NAMESTORE_QueueEntry *add_qe; - - /** - * Response object - */ - json_t *resp_object; - - /** - * The processing state - */ - int state; - - /** - * Handle to NAMESTORE - */ - struct GNUNET_NAMESTORE_Handle *ns_handle; - - /** - * Handle to NAMESTORE it - */ - struct GNUNET_NAMESTORE_ZoneIterator *list_it; - - /** - * Private key for the zone - */ - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_pkey; - - /** - * IDENTITY Operation - */ - struct EgoEntry *ego_entry; - - /** - * Ego list - */ - struct EgoEntry *ego_head; - - /** - * Ego list - */ - struct EgoEntry *ego_tail; - - /** - * IDENTITY Operation - */ - struct GNUNET_IDENTITY_Operation *op; - - /** - * Handle to Identity service. - */ - struct GNUNET_IDENTITY_Handle *identity_handle; - - /** - * Rest connection - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * Desired timeout for the lookup (default is no timeout). - */ - struct GNUNET_TIME_Relative timeout; - - /** - * ID of a task associated with the resolution process. - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * The url - */ - char *url; - - /** - * Error response message - */ - char *emsg; - - /** - * Response code - */ - int response_code; - -}; - -/** - * Cleanup lookup handle - * @param handle Handle to clean up - */ -static void -cleanup_handle (void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct EgoEntry *ego_tmp; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Cleaning up\n"); - if (NULL != handle->timeout_task) - { - GNUNET_SCHEDULER_cancel (handle->timeout_task); - handle->timeout_task = NULL; - } - if (NULL != handle->record_name) - GNUNET_free(handle->record_name); - if (NULL != handle->url) - GNUNET_free(handle->url); - if (NULL != handle->emsg) - GNUNET_free(handle->emsg); - if (NULL != handle->rd) - { - if (NULL != handle->rd->data) - GNUNET_free((void*)handle->rd->data); - GNUNET_free(handle->rd); - } - if (NULL != handle->timeout_task) - GNUNET_SCHEDULER_cancel(handle->timeout_task); - if (NULL != handle->list_it) - GNUNET_NAMESTORE_zone_iteration_stop(handle->list_it); - if (NULL != handle->add_qe) - GNUNET_NAMESTORE_cancel(handle->add_qe); - if (NULL != handle->identity_handle) - GNUNET_IDENTITY_disconnect(handle->identity_handle); - if (NULL != handle->ns_handle) - { - GNUNET_NAMESTORE_disconnect(handle->ns_handle); - } - - for (ego_entry = handle->ego_head; - NULL != ego_entry;) - { - ego_tmp = ego_entry; - ego_entry = ego_entry->next; - GNUNET_free(ego_tmp->identifier); - GNUNET_free(ego_tmp->keystring); - GNUNET_free(ego_tmp); - } - - if(NULL != handle->resp_object) - { - json_decref(handle->resp_object); - } - - GNUNET_free (handle); -} - - -/** - * Task run on errors. Reports an error and cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - json_t *json_error = json_object(); - char *response; - - if (NULL == handle->emsg) - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_ERROR_UNKNOWN); - - json_object_set_new(json_error,"error", json_string(handle->emsg)); - - if (0 == handle->response_code) - handle->response_code = MHD_HTTP_OK; - response = json_dumps (json_error, 0); - resp = GNUNET_REST_create_response (response); - handle->proc (handle->proc_cls, resp, handle->response_code); - json_decref(json_error); - GNUNET_free(response); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Get EgoEntry from list with either a public key or a name - * If public key and name are not NULL, it returns the public key result first - * - * @param handle the RequestHandle - * @param pubkey the public key of an identity (only one can be NULL) - * @param name the name of an identity (only one can be NULL) - * @return EgoEntry or NULL if not found - */ -struct EgoEntry* -get_egoentry_namestore(struct RequestHandle *handle, char *name) -{ - struct EgoEntry *ego_entry; - if (NULL != name) - { - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (0 != strcasecmp (name, ego_entry->identifier)) - continue; - return ego_entry; - } - } - return NULL; -} - - -/** - * Does internal server error when iteration failed. - * - * @param cls the `struct RequestHandle` - */ -static void -namestore_iteration_error (void *cls) -{ - struct RequestHandle *handle = cls; - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; -} - - -/** - * Create finished callback - * - * @param cls the `struct RequestHandle` - * @param success the success indicating integer, GNUNET_OK on success - * @param emsg the error message (can be NULL) - */ -static void -create_finished (void *cls, int32_t success, const char *emsg) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - handle->add_qe = NULL; - if (GNUNET_YES != success) - { - if (NULL != emsg) - { - handle->emsg = GNUNET_strdup(emsg); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->emsg = GNUNET_strdup("Error storing records"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Delete finished callback - * - * @param cls the `struct RequestHandle` - * @param success the success indicating integer, GNUNET_OK on success - * @param emsg the error message (can be NULL) - */ -static void -del_finished (void *cls, int32_t success, const char *emsg) -{ - struct RequestHandle *handle = cls; - - handle->add_qe = NULL; - if (GNUNET_NO == success) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup("No record found"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (GNUNET_SYSERR == success) - { - if (NULL != emsg) - { - handle->emsg = GNUNET_strdup(emsg); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->emsg = GNUNET_strdup("Deleting record failed"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->proc (handle->proc_cls, - GNUNET_REST_create_response (NULL), - MHD_HTTP_NO_CONTENT); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Iteration over all results finished, build final - * response. - * - * @param cls the `struct RequestHandle` - */ -static void -namestore_list_finished (void *cls) -{ - struct RequestHandle *handle = cls; - char *result_str; - struct MHD_Response *resp; - - handle->list_it = NULL; - - if (NULL == handle->resp_object) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - result_str = json_dumps (handle->resp_object, 0); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free_non_null (result_str); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Create a response with requested records - * - * @param handle the RequestHandle - */ -static void -namestore_list_iteration (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, - const char *rname, - unsigned int rd_len, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct RequestHandle *handle = cls; - json_t *record_obj; - - if (NULL == handle->resp_object) - handle->resp_object = json_array(); - - for (unsigned int i = 0; i < rd_len; i++) - { - if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) && - (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)) ) - continue; - - record_obj = GNUNET_JSON_from_gns_record(rname,rd); - - if(NULL == record_obj) - continue; - - json_array_append (handle->resp_object, record_obj); - json_decref (record_obj); - } - - GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1); -} - - -/** - * Handle namestore GET request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -namestore_get (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *egoname; - - egoname = NULL; - ego_entry = NULL; - - //set zone to name if given - if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url)) - { - egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE)+1]; - ego_entry = get_egoentry_namestore(handle, egoname); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - } - if ( NULL != ego_entry ) - { - handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego); - } - if (NULL == handle->zone_pkey) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle, - handle->zone_pkey, - &namestore_iteration_error, - handle, - &namestore_list_iteration, - handle, - &namestore_list_finished, - handle); - if (NULL == handle->list_it) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } -} - - -/** - * Handle namestore POST request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -namestore_add (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_GNSRECORD_Data *gns_record; - struct EgoEntry *ego_entry; - char *egoname; - json_t *data_js; - json_t *name_json; - json_error_t err; - char term_data[handle->rest_handle->data_size + 1]; - - struct GNUNET_JSON_Specification gnsspec[] = { - GNUNET_JSON_spec_gnsrecord_data(&gns_record), - GNUNET_JSON_spec_end () - }; - - if (0 >= handle->rest_handle->data_size) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy(term_data, handle->rest_handle->data, - handle->rest_handle->data_size); - data_js = json_loads (term_data, JSON_DECODE_ANY, &err); - if (GNUNET_OK != GNUNET_JSON_parse (data_js, gnsspec, NULL, NULL)) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - GNUNET_JSON_parse_free(gnsspec); - json_decref (data_js); - return; - } - handle->rd = gns_record; - - name_json = json_object_get(data_js, "record_name"); - if (!json_is_string(name_json)) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - handle->record_name = GNUNET_strdup(json_string_value(name_json)); - if(NULL == handle->record_name) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - if (0 >= strlen(handle->record_name)) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - json_decref (data_js); - - egoname = NULL; - ego_entry = NULL; - - //set zone to name if given - if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url)) - { - egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE)+1]; - ego_entry = get_egoentry_namestore(handle, egoname); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - } - if (NULL != ego_entry) - { - handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego); - } - if (NULL == handle->zone_pkey) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle, - handle->zone_pkey, - handle->record_name, - 1, - handle->rd, - &create_finished, - handle); - if (NULL == handle->add_qe) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } -} - - -/** - * Handle namestore DELETE request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -namestore_delete (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_HashCode key; - struct EgoEntry *ego_entry; - char *egoname; - - egoname = NULL; - ego_entry = NULL; - - //set zone to name if given - if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url)) - { - egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE)+1]; - ego_entry = get_egoentry_namestore(handle, egoname); - - if (NULL == ego_entry) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - } - if ( NULL != ego_entry ) - { - handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego); - } - - GNUNET_CRYPTO_hash ("record_name", strlen ("record_name"), &key); - if ( GNUNET_NO - == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, - &key)) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->record_name = GNUNET_strdup( - GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key)); - - if (NULL == handle->zone_pkey) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle, - handle->zone_pkey, - handle->record_name, - 0, - NULL, - &del_finished, - handle); - if (NULL == handle->add_qe) - { - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } -} - - - -/** - * Respond to OPTIONS request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -options_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - //independent of path return all options - resp = GNUNET_REST_create_response (NULL); - MHD_add_response_header (resp, - "Access-Control-Allow-Methods", - allow_methods); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); - return; -} - - -/** - * Handle rest request - * - * @param handle the request handle - */ -static void -init_cont (struct RequestHandle *handle) -{ - struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = { - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_get}, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_add}, - {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete}, - {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont}, - GNUNET_REST_HANDLER_END - }; - - if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, - handlers, - &err, - handle)) - { - handle->response_code = err.error_code; - GNUNET_SCHEDULER_add_now (&do_error, handle); - } -} - -/** - * @param cls closure - * @param ego ego handle - * @param ctx context for application to store data for this ego - * (during the lifetime of this process, initially NULL) - * @param identifier identifier assigned by the user for this ego, - * NULL if the user just deleted the ego and it - * must thus no longer be used - */ -static void -default_ego_cb (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *identifier) -{ - struct RequestHandle *handle = cls; - handle->op = NULL; - - if (ego != NULL) - { - handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego); - } -} - - -/** - * This function is initially called for all egos and then again - * whenever a ego's identifier changes or if it is deleted. At the - * end of the initial pass over all egos, the function is once called - * with 'NULL' for 'ego'. That does NOT mean that the callback won't - * be invoked in the future or that there was an error. - * - * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', - * this function is only called ONCE, and 'NULL' being passed in - * 'ego' does indicate an error (i.e. name is taken or no default - * value is known). If 'ego' is non-NULL and if '*ctx' - * is set in those callbacks, the value WILL be passed to a subsequent - * call to the identity callback of 'GNUNET_IDENTITY_connect' (if - * that one was not NULL). - * - * When an identity is renamed, this function is called with the - * (known) ego but the NEW identifier. - * - * When an identity is deleted, this function is called with the - * (known) ego and "NULL" for the 'identifier'. In this case, - * the 'ego' is henceforth invalid (and the 'ctx' should also be - * cleaned up). - * - * @param cls closure - * @param ego ego handle - * @param ctx context for application to store data for this ego - * (during the lifetime of this process, initially NULL) - * @param name identifier assigned by the user for this ego, - * NULL if the user just deleted the ego and it - * must thus no longer be used - */ -static void -id_connect_cb (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *name) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct GNUNET_CRYPTO_EcdsaPublicKey pk; - - if ((NULL == ego) && (NULL == handle->zone_pkey)) - { - handle->op = GNUNET_IDENTITY_get (handle->identity_handle, - "namestore", - &default_ego_cb, - handle); - } - if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state)) - { - handle->state = ID_REST_STATE_POST_INIT; - init_cont (handle); - return; - } - if (ID_REST_STATE_INIT == handle->state) - { - ego_entry = GNUNET_new(struct EgoEntry); - GNUNET_IDENTITY_ego_get_public_key (ego, &pk); - ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); - ego_entry->ego = ego; - GNUNET_asprintf (&ego_entry->identifier, "%s", name); - GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail, - ego_entry); - } - -} - - -/** - * Function processing the REST call - * - * @param method HTTP method - * @param url URL of the HTTP request - * @param data body of the HTTP request (optional) - * @param data_size length of the body - * @param proc callback function for the result - * @param proc_cls closure for callback function - * @return GNUNET_OK if request accepted - */ -static void -rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) -{ - struct RequestHandle *handle = GNUNET_new (struct RequestHandle); - - handle->response_code = 0; - handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; - handle->proc_cls = proc_cls; - handle->proc = proc; - handle->rest_handle = rest_handle; - handle->zone_pkey = NULL; - - handle->url = GNUNET_strdup (rest_handle->url); - if (handle->url[strlen (handle->url)-1] == '/') - handle->url[strlen (handle->url)-1] = '\0'; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); - - handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &id_connect_cb, handle); - handle->ns_handle = GNUNET_NAMESTORE_connect (cfg); - handle->timeout_task = - GNUNET_SCHEDULER_add_delayed (handle->timeout, - &do_error, - handle); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); -} - - -/** - * Entry point for the plugin. - * - * @param cls Config info - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_rest_namestore_init (void *cls) -{ - static struct Plugin plugin; - struct GNUNET_REST_Plugin *api; - - cfg = cls; - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof (struct Plugin)); - plugin.cfg = cfg; - api = GNUNET_new (struct GNUNET_REST_Plugin); - api->cls = &plugin; - api->name = GNUNET_REST_API_NS_NAMESTORE; - api->process_request = &rest_process_request; - GNUNET_asprintf (&allow_methods, - "%s, %s, %s, %s, %s", - MHD_HTTP_METHOD_GET, - MHD_HTTP_METHOD_POST, - MHD_HTTP_METHOD_PUT, - MHD_HTTP_METHOD_DELETE, - MHD_HTTP_METHOD_OPTIONS); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _("Namestore REST API initialized\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ -void * -libgnunet_plugin_rest_namestore_done (void *cls) -{ - struct GNUNET_REST_Plugin *api = cls; - struct Plugin *plugin = api->cls; - plugin->cfg = NULL; - - GNUNET_free_non_null (allow_methods); - GNUNET_free (api); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Namestore REST plugin is finished\n"); - return NULL; -} - -/* end of plugin_rest_namestore.c */ - diff --git a/src/peerinfo/Makefile.am b/src/peerinfo/Makefile.am index 5e96250b1..3f68becb5 100644 --- a/src/peerinfo/Makefile.am +++ b/src/peerinfo/Makefile.am @@ -27,8 +27,6 @@ libgnunetpeerinfo_la_SOURCES = \ libgnunetpeerinfo_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/json/libgnunetjson.la \ - $(top_builddir)/src/transport/libgnunettransport.la \ $(XLIB) \ $(LTLIBINTL) libgnunetpeerinfo_la_LDFLAGS = \ @@ -39,13 +37,6 @@ libgnunetpeerinfo_la_LDFLAGS = \ libexec_PROGRAMS = \ gnunet-service-peerinfo -if HAVE_MHD -if HAVE_JSON -plugin_LTLIBRARIES = \ - libgnunet_plugin_rest_peerinfo.la -endif -endif - gnunet_service_peerinfo_SOURCES = \ gnunet-service-peerinfo.c gnunet_service_peerinfo_LDADD = \ @@ -53,17 +44,6 @@ gnunet_service_peerinfo_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la - -libgnunet_plugin_rest_peerinfo_la_SOURCES = \ - plugin_rest_peerinfo.c -libgnunet_plugin_rest_peerinfo_la_LIBADD = \ - libgnunetpeerinfo.la \ - $(top_builddir)/src/rest/libgnunetrest.la \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -ljansson -lmicrohttpd -libgnunet_plugin_rest_peerinfo_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - if HAVE_BENCHMARKS PEERINFO_BENCHMARKS = \ perf_peerinfo_api diff --git a/src/peerinfo/plugin_rest_peerinfo.c b/src/peerinfo/plugin_rest_peerinfo.c deleted file mode 100644 index 29b40088d..000000000 --- a/src/peerinfo/plugin_rest_peerinfo.c +++ /dev/null @@ -1,820 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -/** - * @author Martin Schanzenbach - * @author Philippe Buschmann - * @file peerinfo/plugin_rest_peerinfo.c - * @brief GNUnet Peerinfo REST plugin - */ - -#include "platform.h" -#include "gnunet_rest_plugin.h" -#include "gnunet_peerinfo_service.h" -#include "gnunet_transport_service.h" -#include "gnunet_rest_lib.h" -#include "gnunet_json_lib.h" -#include "microhttpd.h" -#include - -/** - * Peerinfo Namespace - */ -#define GNUNET_REST_API_NS_PEERINFO "/peerinfo" - -/** - * Peerinfo parameter peer - */ -#define GNUNET_REST_PEERINFO_PEER "peer" - -/** - * Peerinfo parameter friend - */ -#define GNUNET_REST_PEERINFO_FRIEND "friend" - -/** - * Peerinfo parameter array - */ -#define GNUNET_REST_PEERINFO_ARRAY "array" - -/** - * Error message Unknown Error - */ -#define GNUNET_REST_PEERINFO_ERROR_UNKNOWN "Unknown Error" - -/** - * How long until we time out during address lookup? - */ -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) -/** - * The configuration handle - */ -const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * HTTP methods allows for this plugin - */ -static char* allow_methods; - -/** - * @brief struct returned by the initialization function of the plugin - */ -struct Plugin -{ - const struct GNUNET_CONFIGURATION_Handle *cfg; -}; - - -/** - * Record we keep for each printable address. - */ -struct AddressRecord -{ - /** - * Current address-to-string context (if active, otherwise NULL). - */ - struct GNUNET_TRANSPORT_AddressToStringContext *atsc; - - /** - * Address expiration time - */ - struct GNUNET_TIME_Absolute expiration; - - /** - * Printable address. - */ - char *result; - - /** - * Print context this address record belongs to. - */ - struct PrintContext *pc; -}; - - -/** - * Structure we use to collect printable address information. - */ -struct PrintContext -{ - /** - * Kept in DLL. - */ - struct PrintContext *next; - - /** - * Kept in DLL. - */ - struct PrintContext *prev; - - /** - * Identity of the peer. - */ - struct GNUNET_PeerIdentity peer; - - /** - * List of printable addresses. - */ - struct AddressRecord *address_list; - - /** - * Number of completed addresses in @e address_list. - */ - unsigned int num_addresses; - - /** - * Number of addresses allocated in @e address_list. - */ - unsigned int address_list_size; - - /** - * Current offset in @e address_list (counted down). - */ - unsigned int off; - - /** - * Hello was friend only, #GNUNET_YES or #GNUNET_NO - */ - int friend_only; - - /** - * RequestHandle - */ - struct RequestHandle *handle; - -}; - -/** - * Head of list of print contexts. - */ -static struct PrintContext *pc_head; - -/** - * Tail of list of print contexts. - */ -static struct PrintContext *pc_tail; - -/** - * The request handle - */ -struct RequestHandle -{ - /** - * JSON temporary array - */ - json_t *temp_array; - - /** - * Expiration time string - */ - char *expiration_str; - - /** - * Address string - */ - const char *address; - - /** - * Iteration peer public key - */ - char *pubkey; - - /** - * JSON response - */ - json_t *response; - - /** - * Handle to PEERINFO it - */ - struct GNUNET_PEERINFO_IteratorContext *list_it; - - /** - * Handle to PEERINFO - */ - struct GNUNET_PEERINFO_Handle *peerinfo_handle; - - /** - * Rest connection - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * Desired timeout for the lookup (default is no timeout). - */ - struct GNUNET_TIME_Relative timeout; - - /** - * ID of a task associated with the resolution process. - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * The url - */ - char *url; - - /** - * Error response message - */ - char *emsg; - - /** - * Reponse code - */ - int response_code; - -}; - - -/** - * Cleanup lookup handle - * @param handle Handle to clean up - */ -static void -cleanup_handle (void *cls) -{ - struct RequestHandle *handle = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Cleaning up\n"); - if (NULL != handle->timeout_task) - { - GNUNET_SCHEDULER_cancel (handle->timeout_task); - handle->timeout_task = NULL; - } - if (NULL != handle->url) - GNUNET_free (handle->url); - if (NULL != handle->emsg) - GNUNET_free (handle->emsg); - if (NULL != handle->address) - GNUNET_free ((char*)handle->address); - if (NULL != handle->expiration_str) - GNUNET_free (handle->expiration_str); - if (NULL != handle->pubkey) - GNUNET_free (handle->pubkey); - - if (NULL != handle->temp_array) - { - json_decref(handle->temp_array); - handle->temp_array = NULL; - } - if (NULL != handle->response) - { - json_decref(handle->response); - handle->response = NULL; - } - - if (NULL != handle->list_it) - { - GNUNET_PEERINFO_iterate_cancel(handle->list_it); - handle->list_it = NULL; - } - if (NULL != handle->peerinfo_handle) - { - GNUNET_PEERINFO_disconnect(handle->peerinfo_handle); - handle->peerinfo_handle = NULL; - } - - GNUNET_free (handle); -} - - -/** - * Task run on errors. Reports an error and cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - json_t *json_error = json_object(); - char *response; - - if (NULL == handle->emsg) - handle->emsg = GNUNET_strdup(GNUNET_REST_PEERINFO_ERROR_UNKNOWN); - - json_object_set_new(json_error,"error", json_string(handle->emsg)); - - if (0 == handle->response_code) - handle->response_code = MHD_HTTP_OK; - response = json_dumps (json_error, 0); - resp = GNUNET_REST_create_response (response); - handle->proc (handle->proc_cls, resp, handle->response_code); - json_decref(json_error); - GNUNET_free(response); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Function that assembles the response. - * - * @param cls the `struct RequestHandle` - */ -static void -peerinfo_list_finished (void *cls) -{ - struct RequestHandle *handle = cls; - char *result_str; - struct MHD_Response *resp; - - if (NULL == handle->response) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup ("No peers found"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - result_str = json_dumps (handle->response, 0); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free_non_null (result_str); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Iterator callback to go over all addresses and count them. - * - * @param cls `struct PrintContext *` with `off` to increment - * @param address the address - * @param expiration expiration time - * @return #GNUNET_OK to keep the address and continue - */ -static int -count_address (void *cls, - const struct GNUNET_HELLO_Address *address, - struct GNUNET_TIME_Absolute expiration) -{ - struct PrintContext *pc = cls; - - if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us) - { - return GNUNET_OK; /* ignore expired address */ - } - - pc->off++; - return GNUNET_OK; -} - - -/** - * Print the collected address information to the console and free @a pc. - * - * @param pc printing context - */ -static void -dump_pc (struct PrintContext *pc) -{ - struct RequestHandle *handle; - unsigned int i; - json_t *response_entry; - json_t *temp_array; - json_t *object; - json_t *address; - json_t *expires; - json_t *friend_and_peer_json; - char *friend_and_peer; - - temp_array = json_array(); - response_entry = json_object(); - - for (i = 0; i < pc->num_addresses; i++) - { - if (NULL != pc->address_list[i].result) - { - object = json_object (); - address = json_string(pc->address_list[i].result); - expires = json_string( - GNUNET_STRINGS_absolute_time_to_string (pc->address_list[i].expiration)); - json_object_set (object, "address", address); - json_object_set (object, "expires", expires); - - json_decref(address); - json_decref(expires); - - json_array_append(temp_array, object); - json_decref(object); - GNUNET_free (pc->address_list[i].result); - } - } - - if (0 < json_array_size(temp_array)) - { - GNUNET_asprintf(&friend_and_peer, - "%s%s", - (GNUNET_YES == pc->friend_only) ? "F2F:" : "", - GNUNET_i2s_full (&pc->peer)); - friend_and_peer_json = json_string(friend_and_peer); - json_object_set(response_entry, - GNUNET_REST_PEERINFO_PEER, - friend_and_peer_json); - json_object_set(response_entry, - GNUNET_REST_PEERINFO_ARRAY, - temp_array); - json_array_append(pc->handle->response, response_entry); - json_decref(friend_and_peer_json); - GNUNET_free(friend_and_peer); - } - - json_decref (temp_array); - json_decref(response_entry); - - GNUNET_free_non_null (pc->address_list); - GNUNET_CONTAINER_DLL_remove (pc_head, - pc_tail, - pc); - handle = pc->handle; - GNUNET_free (pc); - - if ( (NULL == pc_head) && - (NULL == handle->list_it) ) - { - GNUNET_SCHEDULER_add_now (&peerinfo_list_finished, handle); - } - -} - - -/** - * Function to call with a human-readable format of an address - * - * @param cls closure - * @param address NULL on error, otherwise 0-terminated printable UTF-8 string - * @param res result of the address to string conversion: - * if #GNUNET_OK: address was valid (conversion to - * string might still have failed) - * if #GNUNET_SYSERR: address is invalid - */ -static void -process_resolved_address (void *cls, - const char *address, - int res) -{ - struct AddressRecord *ar = cls; - struct PrintContext *pc = ar->pc; - - if (NULL != address) - { - if (0 != strlen (address)) - { - if (NULL != ar->result) - GNUNET_free (ar->result); - ar->result = GNUNET_strdup (address); - } - return; - } - ar->atsc = NULL; - if (GNUNET_SYSERR == res) - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Failure: Cannot convert address to string for peer `%s'\n"), - GNUNET_i2s (&ar->pc->peer)); - pc->num_addresses++; - if (pc->num_addresses == pc->address_list_size) - dump_pc (ar->pc); -} - - -/** - * Iterator callback to go over all addresses. - * - * @param cls closure - * @param address the address - * @param expiration expiration time - * @return #GNUNET_OK to keep the address and continue - */ -static int -print_address (void *cls, - const struct GNUNET_HELLO_Address *address, - struct GNUNET_TIME_Absolute expiration) -{ - struct PrintContext *pc = cls; - struct AddressRecord *ar; - - if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us) - { - return GNUNET_OK; /* ignore expired address */ - } - - GNUNET_assert (0 < pc->off); - ar = &pc->address_list[--pc->off]; - ar->pc = pc; - ar->expiration = expiration; - GNUNET_asprintf (&ar->result, - "%s:%u:%u", - address->transport_name, - address->address_length, - address->local_info); - ar->atsc = GNUNET_TRANSPORT_address_to_string (cfg, - address, - GNUNET_NO, - TIMEOUT, - &process_resolved_address, - ar); - return GNUNET_OK; -} - - -/** - * Callback that processes each of the known HELLOs for the - * iteration response construction. - * - * @param cls closure, NULL - * @param peer id of the peer, NULL for last call - * @param hello hello message for the peer (can be NULL) - * @param err_msg message - */ -void -peerinfo_list_iteration(void *cls, - const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_HELLO_Message *hello, - const char *err_msg) -{ - struct RequestHandle *handle = cls; - struct PrintContext *pc; - int friend_only; - - if (NULL == handle->response) - { - handle->response = json_array(); - } - - if (NULL == peer) - { - handle->list_it = NULL; - handle->emsg = GNUNET_strdup ("Error in communication with peerinfo"); - if (NULL != err_msg) - { - GNUNET_free(handle->emsg); - handle->emsg = GNUNET_strdup (err_msg); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - } - if (NULL == pc_head) - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (NULL == hello) - return; - - friend_only = GNUNET_NO; - if (NULL != hello) - friend_only = GNUNET_HELLO_is_friend_only (hello); - - pc = GNUNET_new(struct PrintContext); - GNUNET_CONTAINER_DLL_insert (pc_head, - pc_tail, - pc); - pc->peer = *peer; - pc->friend_only = friend_only; - pc->handle = handle; - GNUNET_HELLO_iterate_addresses (hello, - GNUNET_NO, - &count_address, - pc); - if (0 == pc->off) - { - dump_pc (pc); - return; - } - pc->address_list_size = pc->off; - pc->address_list = GNUNET_malloc( - sizeof(struct AddressRecord) * pc->off); - GNUNET_HELLO_iterate_addresses (hello, - GNUNET_NO, - &print_address, - pc); -} - -/** - * Handle peerinfo GET request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -peerinfo_get (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_HashCode key; - const struct GNUNET_PeerIdentity *specific_peer; - //GNUNET_PEER_Id peer_id; - int include_friend_only; - char* include_friend_only_str; - - include_friend_only = GNUNET_NO; - GNUNET_CRYPTO_hash (GNUNET_REST_PEERINFO_FRIEND, - strlen (GNUNET_REST_PEERINFO_FRIEND), - &key); - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, - &key)) - { - include_friend_only_str = GNUNET_CONTAINER_multihashmap_get ( - con_handle->url_param_map, &key); - if (0 == strcmp(include_friend_only_str, "yes")) - { - include_friend_only = GNUNET_YES; - } - } - - specific_peer = NULL; - GNUNET_CRYPTO_hash (GNUNET_REST_PEERINFO_PEER, - strlen (GNUNET_REST_PEERINFO_PEER), - &key); - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, - &key)) - { - //peer_id = *(unsigned int*)GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key); - //specific_peer = GNUNET_PEER_resolve2(peer_id); - } - - handle->list_it = GNUNET_PEERINFO_iterate(handle->peerinfo_handle, - include_friend_only, - specific_peer, - &peerinfo_list_iteration, - handle); -} - - - -/** - * Respond to OPTIONS request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -options_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - //independent of path return all options - resp = GNUNET_REST_create_response (NULL); - MHD_add_response_header (resp, - "Access-Control-Allow-Methods", - allow_methods); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); - return; -} - - -/** - * Handle rest request - * - * @param handle the request handle - */ -static void -init_cont (struct RequestHandle *handle) -{ - struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = { - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_PEERINFO, &peerinfo_get}, - {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_PEERINFO, &options_cont}, - GNUNET_REST_HANDLER_END - }; - - if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, - handlers, - &err, - handle)) - { - handle->response_code = err.error_code; - GNUNET_SCHEDULER_add_now (&do_error, handle); - } -} - - -/** - * Function processing the REST call - * - * @param method HTTP method - * @param url URL of the HTTP request - * @param data body of the HTTP request (optional) - * @param data_size length of the body - * @param proc callback function for the result - * @param proc_cls closure for callback function - * @return GNUNET_OK if request accepted - */ -static void -rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) -{ - struct RequestHandle *handle = GNUNET_new (struct RequestHandle); - - handle->response_code = 0; - handle->timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60); - handle->proc_cls = proc_cls; - handle->proc = proc; - handle->rest_handle = rest_handle; - - handle->url = GNUNET_strdup (rest_handle->url); - if (handle->url[strlen (handle->url)-1] == '/') - handle->url[strlen (handle->url)-1] = '\0'; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); - handle->peerinfo_handle = GNUNET_PEERINFO_connect(cfg); - init_cont(handle); - handle->timeout_task = - GNUNET_SCHEDULER_add_delayed (handle->timeout, - &do_error, - handle); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); -} - - -/** - * Entry point for the plugin. - * - * @param cls Config info - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_rest_peerinfo_init (void *cls) -{ - static struct Plugin plugin; - struct GNUNET_REST_Plugin *api; - - cfg = cls; - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof (struct Plugin)); - plugin.cfg = cfg; - api = GNUNET_new (struct GNUNET_REST_Plugin); - api->cls = &plugin; - api->name = GNUNET_REST_API_NS_PEERINFO; - api->process_request = &rest_process_request; - GNUNET_asprintf (&allow_methods, - "%s, %s, %s, %s, %s", - MHD_HTTP_METHOD_GET, - MHD_HTTP_METHOD_POST, - MHD_HTTP_METHOD_PUT, - MHD_HTTP_METHOD_DELETE, - MHD_HTTP_METHOD_OPTIONS); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _("Peerinfo REST API initialized\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ -void * -libgnunet_plugin_rest_peerinfo_done (void *cls) -{ - struct GNUNET_REST_Plugin *api = cls; - struct Plugin *plugin = api->cls; - plugin->cfg = NULL; - - GNUNET_free_non_null (allow_methods); - GNUNET_free (api); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Peerinfo REST plugin is finished\n"); - return NULL; -} - -/* end of plugin_rest_peerinfo.c */ - diff --git a/src/reclaim/Makefile.am b/src/reclaim/Makefile.am index 2ee43d21a..093442181 100644 --- a/src/reclaim/Makefile.am +++ b/src/reclaim/Makefile.am @@ -31,8 +31,6 @@ pkgcfg_DATA = \ lib_LTLIBRARIES = \ libgnunetreclaim.la plugin_LTLIBRARIES = \ - libgnunet_plugin_rest_reclaim.la \ - libgnunet_plugin_rest_openid_connect.la \ libgnunet_plugin_gnsrecord_reclaim.la \ $(SQLITE_PLUGIN) @@ -88,37 +86,6 @@ libgnunetreclaim_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 -libgnunet_plugin_rest_reclaim_la_SOURCES = \ - plugin_rest_reclaim.c -libgnunet_plugin_rest_reclaim_la_LIBADD = \ - $(top_builddir)/src/identity/libgnunetidentity.la \ - libgnunetreclaim.la \ - $(top_builddir)/src/rest/libgnunetrest.la \ - $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \ - $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \ - $(top_builddir)/src/namestore/libgnunetnamestore.la \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -ljansson -lmicrohttpd -libgnunet_plugin_rest_reclaim_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - -libgnunet_plugin_rest_openid_connect_la_SOURCES = \ - plugin_rest_openid_connect.c \ - oidc_helper.c -libgnunet_plugin_rest_openid_connect_la_LIBADD = \ - $(top_builddir)/src/identity/libgnunetidentity.la \ - libgnunetreclaim.la \ - $(top_builddir)/src/rest/libgnunetrest.la \ - $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \ - $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \ - $(top_builddir)/src/namestore/libgnunetnamestore.la \ - $(top_builddir)/src/gns/libgnunetgns.la \ - $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -ljansson -lmicrohttpd -libgnunet_plugin_rest_openid_connect_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - gnunet_reclaim_SOURCES = \ gnunet-reclaim.c gnunet_reclaim_LDADD = \ diff --git a/src/reclaim/oidc_helper.c b/src/reclaim/oidc_helper.c deleted file mode 100644 index 1e9e64fec..000000000 --- a/src/reclaim/oidc_helper.c +++ /dev/null @@ -1,440 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2010-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ - -/** - * @file reclaim/oidc_helper.c - * @brief helper library for OIDC related functions - * @author Martin Schanzenbach - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_signatures.h" -#include "gnunet_reclaim_service.h" -#include "gnunet_reclaim_attribute_lib.h" -#include -#include -#include "oidc_helper.h" - -static char* -create_jwt_header(void) -{ - json_t *root; - char *json_str; - - root = json_object (); - json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE)); - json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE)); - - json_str = json_dumps (root, JSON_INDENT(0) | JSON_COMPACT); - json_decref (root); - return json_str; -} - -static void -replace_char(char* str, char find, char replace){ - char *current_pos = strchr(str,find); - while (current_pos){ - *current_pos = replace; - current_pos = strchr(current_pos,find); - } -} - -//RFC4648 -static void -fix_base64(char* str) { - char *padding; - //First, remove trailing padding '=' - padding = strtok(str, "="); - while (NULL != padding) - padding = strtok(NULL, "="); - - //Replace + with - - replace_char (str, '+', '-'); - - //Replace / with _ - replace_char (str, '/', '_'); - -} - -/** - * Create a JWT from attributes - * - * @param aud_key the public of the audience - * @param sub_key the public key of the subject - * @param attrs the attribute list - * @param expiration_time the validity of the token - * @param secret_key the key used to sign the JWT - * @return a new base64-encoded JWT string. - */ -char* -OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, - const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, - const struct GNUNET_TIME_Relative *expiration_time, - const char *nonce, - const char *secret_key) -{ - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; - struct GNUNET_HashCode signature; - struct GNUNET_TIME_Absolute exp_time; - struct GNUNET_TIME_Absolute time_now; - char* audience; - char* subject; - char* header; - char* body_str; - char* result; - char* header_base64; - char* body_base64; - char* signature_target; - char* signature_base64; - char* attr_val_str; - json_t* body; - - //iat REQUIRED time now - time_now = GNUNET_TIME_absolute_get(); - //exp REQUIRED time expired from config - exp_time = GNUNET_TIME_absolute_add (time_now, *expiration_time); - //auth_time only if max_age - //nonce only if nonce - // OPTIONAL acr,amr,azp - subject = GNUNET_STRINGS_data_to_string_alloc (sub_key, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - audience = GNUNET_STRINGS_data_to_string_alloc (aud_key, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - header = create_jwt_header (); - body = json_object (); - - //iss REQUIRED case sensitive server uri with https - //The issuer is the local reclaim instance (e.g. https://reclaim.id/api/openid) - json_object_set_new (body, - "iss", json_string (SERVER_ADDRESS)); - //sub REQUIRED public key identity, not exceed 255 ASCII length - json_object_set_new (body, - "sub", json_string (subject)); - //aud REQUIRED public key client_id must be there - json_object_set_new (body, - "aud", json_string (audience)); - //iat - json_object_set_new (body, - "iat", json_integer (time_now.abs_value_us / (1000*1000))); - //exp - json_object_set_new (body, - "exp", json_integer (exp_time.abs_value_us / (1000*1000))); - //nbf - json_object_set_new (body, - "nbf", json_integer (time_now.abs_value_us / (1000*1000))); - //nonce - if (NULL != nonce) - json_object_set_new (body, - "nonce", json_string (nonce)); - - for (le = attrs->list_head; NULL != le; le = le->next) - { - attr_val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (le->claim->type, - le->claim->data, - le->claim->data_size); - json_object_set_new (body, - le->claim->name, - json_string (attr_val_str)); - GNUNET_free (attr_val_str); - } - body_str = json_dumps (body, JSON_INDENT(0) | JSON_COMPACT); - json_decref (body); - - GNUNET_STRINGS_base64_encode (header, - strlen (header), - &header_base64); - fix_base64(header_base64); - - GNUNET_STRINGS_base64_encode (body_str, - strlen (body_str), - &body_base64); - fix_base64(body_base64); - - GNUNET_free (subject); - GNUNET_free (audience); - - /** - * Creating the JWT signature. This might not be - * standards compliant, check. - */ - GNUNET_asprintf (&signature_target, "%s.%s", header_base64, body_base64); - GNUNET_CRYPTO_hmac_raw (secret_key, strlen (secret_key), signature_target, strlen (signature_target), &signature); - GNUNET_STRINGS_base64_encode ((const char*)&signature, - sizeof (struct GNUNET_HashCode), - &signature_base64); - fix_base64(signature_base64); - - GNUNET_asprintf (&result, "%s.%s.%s", - header_base64, body_base64, signature_base64); - - GNUNET_free (signature_target); - GNUNET_free (header); - GNUNET_free (body_str); - GNUNET_free (signature_base64); - GNUNET_free (body_base64); - GNUNET_free (header_base64); - return result; -} -/** - * Builds an OIDC authorization code including - * a reclaim ticket and nonce - * - * @param issuer the issuer of the ticket, used to sign the ticket and nonce - * @param ticket the ticket to include in the code - * @param nonce the nonce to include in the code - * @return a new authorization code (caller must free) - */ -char* -OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, - const struct GNUNET_RECLAIM_Ticket *ticket, - const char* nonce) -{ - char *ticket_str; - json_t *code_json; - char *signature_payload; - char *signature_str; - char *authz_code; - size_t signature_payload_len; - struct GNUNET_CRYPTO_EcdsaSignature signature; - struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; - - signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket); - if (NULL != nonce) - signature_payload_len += strlen (nonce); - - signature_payload = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len); - purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *)signature_payload; - purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len); - purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN); - memcpy (&purpose[1], - ticket, - sizeof (struct GNUNET_RECLAIM_Ticket)); - if (NULL != nonce) - memcpy (((char*)&purpose[1]) + sizeof (struct GNUNET_RECLAIM_Ticket), - nonce, - strlen (nonce)); - if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdsa_sign (issuer, - purpose, - &signature)) - { - GNUNET_free (signature_payload); - return NULL; - } - signature_str = GNUNET_STRINGS_data_to_string_alloc (&signature, - sizeof (signature)); - ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket, - sizeof (struct GNUNET_RECLAIM_Ticket)); - - code_json = json_object (); - json_object_set_new (code_json, - "ticket", - json_string (ticket_str)); - if (NULL != nonce) - json_object_set_new (code_json, - "nonce", - json_string (nonce)); - json_object_set_new (code_json, - "signature", - json_string (signature_str)); - authz_code = json_dumps (code_json, - JSON_INDENT(0) | JSON_COMPACT); - GNUNET_free (signature_payload); - GNUNET_free (signature_str); - GNUNET_free (ticket_str); - json_decref (code_json); - return authz_code; -} - - - - -/** - * Parse reclaim ticket and nonce from - * authorization code. - * This also verifies the signature in the code. - * - * @param audience the expected audience of the code - * @param code the string representation of the code - * @param ticket where to store the ticket - * @param nonce where to store the nonce - * @return GNUNET_OK if successful, else GNUNET_SYSERR - */ -int -OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience, - const char* code, - struct GNUNET_RECLAIM_Ticket **ticket, - char **nonce) -{ - json_error_t error; - json_t *code_json; - json_t *ticket_json; - json_t *nonce_json; - json_t *signature_json; - const char *ticket_str; - const char *signature_str; - const char *nonce_str; - char *code_output; - struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; - struct GNUNET_CRYPTO_EcdsaSignature signature; - size_t signature_payload_len; - - code_output = NULL; - GNUNET_STRINGS_base64_decode (code, - strlen(code), - (void**)&code_output); - code_json = json_loads (code_output, 0 , &error); - GNUNET_free (code_output); - ticket_json = json_object_get (code_json, "ticket"); - nonce_json = json_object_get (code_json, "nonce"); - signature_json = json_object_get (code_json, "signature"); - *ticket = NULL; - *nonce = NULL; - - if ((NULL == ticket_json || !json_is_string (ticket_json)) || - (NULL == signature_json || !json_is_string (signature_json))) - { - json_decref (code_json); - return GNUNET_SYSERR; - } - ticket_str = json_string_value (ticket_json); - signature_str = json_string_value (signature_json); - nonce_str = NULL; - if (NULL != nonce_json) - nonce_str = json_string_value (nonce_json); - signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket); - if (NULL != nonce_str) - signature_payload_len += strlen (nonce_str); - purpose = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + - signature_payload_len); - purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len); - purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN); - if (GNUNET_OK != GNUNET_STRINGS_string_to_data (ticket_str, - strlen (ticket_str), - &purpose[1], - sizeof (struct GNUNET_RECLAIM_Ticket))) - { - GNUNET_free (purpose); - json_decref (code_json); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Cannot parse ticket!\n"); - return GNUNET_SYSERR; - } - if (GNUNET_OK != GNUNET_STRINGS_string_to_data (signature_str, - strlen (signature_str), - &signature, - sizeof (struct GNUNET_CRYPTO_EcdsaSignature))) - { - GNUNET_free (purpose); - json_decref (code_json); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Cannot parse signature!\n"); - return GNUNET_SYSERR; - } - *ticket = GNUNET_new (struct GNUNET_RECLAIM_Ticket); - memcpy (*ticket, - &purpose[1], - sizeof (struct GNUNET_RECLAIM_Ticket)); - if (0 != memcmp (audience, - &(*ticket)->audience, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) - { - GNUNET_free (purpose); - GNUNET_free (*ticket); - json_decref (code_json); - *ticket = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Audience in ticket does not match client!\n"); - return GNUNET_SYSERR; - - } - if (NULL != nonce_str) - memcpy (((char*)&purpose[1]) + sizeof (struct GNUNET_RECLAIM_Ticket), - nonce_str, - strlen (nonce_str)); - if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN, - purpose, - &signature, - &(*ticket)->identity)) - { - GNUNET_free (purpose); - GNUNET_free (*ticket); - json_decref (code_json); - *ticket = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Signature of authZ code invalid!\n"); - return GNUNET_SYSERR; - } - *nonce = GNUNET_strdup (nonce_str); - return GNUNET_OK; -} - -/** - * Build a token response for a token request - * TODO: Maybe we should add the scope here? - * - * @param access_token the access token to include - * @param id_token the id_token to include - * @param expiration_time the expiration time of the token(s) - * @param token_response where to store the response - */ -void -OIDC_build_token_response (const char *access_token, - const char *id_token, - const struct GNUNET_TIME_Relative *expiration_time, - char **token_response) -{ - json_t *root_json; - - root_json = json_object (); - - GNUNET_assert (NULL != access_token); - GNUNET_assert (NULL != id_token); - GNUNET_assert (NULL != expiration_time); - json_object_set_new (root_json, - "access_token", - json_string (access_token)); - json_object_set_new (root_json, - "token_type", - json_string ("Bearer")); - json_object_set_new (root_json, - "expires_in", - json_integer (expiration_time->rel_value_us / (1000 * 1000))); - json_object_set_new (root_json, - "id_token", - json_string (id_token)); - *token_response = json_dumps (root_json, - JSON_INDENT(0) | JSON_COMPACT); - json_decref (root_json); -} - -/** - * Generate a new access token - */ -char* -OIDC_access_token_new () -{ - char* access_token_number; - char* access_token; - uint64_t random_number; - - random_number = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); - GNUNET_asprintf (&access_token_number, "%" PRIu64, random_number); - GNUNET_STRINGS_base64_encode(access_token_number,strlen(access_token_number),&access_token); - return access_token; -} diff --git a/src/reclaim/oidc_helper.h b/src/reclaim/oidc_helper.h deleted file mode 100644 index 7a0f45bf9..000000000 --- a/src/reclaim/oidc_helper.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2010-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ - -/** - * @file reclaim/oidc_helper.h - * @brief helper library for OIDC related functions - * @author Martin Schanzenbach - */ - -#ifndef JWT_H -#define JWT_H - -#define JWT_ALG "alg" - -/* Use 512bit HMAC */ -#define JWT_ALG_VALUE "HS512" - -#define JWT_TYP "typ" - -#define JWT_TYP_VALUE "jwt" - -#define SERVER_ADDRESS "https://reclaim.id" - -/** - * Create a JWT from attributes - * - * @param aud_key the public of the audience - * @param sub_key the public key of the subject - * @param attrs the attribute list - * @param expiration_time the validity of the token - * @param secret_key the key used to sign the JWT - * @return a new base64-encoded JWT string. - */ -char* -OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, - const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, - const struct GNUNET_TIME_Relative *expiration_time, - const char *nonce, - const char *secret_key); - -/** - * Builds an OIDC authorization code including - * a reclaim ticket and nonce - * - * @param issuer the issuer of the ticket, used to sign the ticket and nonce - * @param ticket the ticket to include in the code - * @param nonce the nonce to include in the code - * @return a new authorization code (caller must free) - */ -char* -OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, - const struct GNUNET_RECLAIM_Ticket *ticket, - const char* nonce); - -/** - * Parse reclaim ticket and nonce from - * authorization code. - * This also verifies the signature in the code. - * - * @param audience the expected audience of the code - * @param code the string representation of the code - * @param ticket where to store the ticket - * @param nonce where to store the nonce - * @return GNUNET_OK if successful, else GNUNET_SYSERR - */ -int -OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience, - const char* code, - struct GNUNET_RECLAIM_Ticket **ticket, - char **nonce); - -/** - * Build a token response for a token request - * TODO: Maybe we should add the scope here? - * - * @param access_token the access token to include - * @param id_token the id_token to include - * @param expiration_time the expiration time of the token(s) - * @param token_response where to store the response - */ -void -OIDC_build_token_response (const char *access_token, - const char *id_token, - const struct GNUNET_TIME_Relative *expiration_time, - char **token_response); -/** - * Generate a new access token - */ -char* -OIDC_access_token_new (); - - -#endif diff --git a/src/reclaim/plugin_rest_openid_connect.c b/src/reclaim/plugin_rest_openid_connect.c deleted file mode 100644 index 24673c692..000000000 --- a/src/reclaim/plugin_rest_openid_connect.c +++ /dev/null @@ -1,2171 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -/** - * @author Martin Schanzenbach - * @author Philippe Buschmann - * @file identity/plugin_rest_openid_connect.c - * @brief GNUnet Namestore REST plugin - * - */ - -#include "platform.h" -#include "gnunet_rest_plugin.h" -#include "gnunet_identity_service.h" -#include "gnunet_gns_service.h" -#include "gnunet_gnsrecord_lib.h" -#include "gnunet_namestore_service.h" -#include "gnunet_rest_lib.h" -#include "gnunet_jsonapi_lib.h" -#include "gnunet_jsonapi_util.h" -#include "microhttpd.h" -#include -#include -#include "gnunet_signatures.h" -#include "gnunet_reclaim_attribute_lib.h" -#include "gnunet_reclaim_service.h" -#include "oidc_helper.h" - -/** - * REST root namespace - */ -#define GNUNET_REST_API_NS_OIDC "/openid" - -/** - * Authorize endpoint - */ -#define GNUNET_REST_API_NS_AUTHORIZE "/openid/authorize" - -/** - * Token endpoint - */ -#define GNUNET_REST_API_NS_TOKEN "/openid/token" - -/** - * UserInfo endpoint - */ -#define GNUNET_REST_API_NS_USERINFO "/openid/userinfo" - -/** - * Login namespace - */ -#define GNUNET_REST_API_NS_LOGIN "/openid/login" - -/** - * Attribute key - */ -#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE "attribute" - -/** - * Ticket key - */ -#define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket" - - -/** - * Value key - */ -#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE_VALUE "value" - -/** - * State while collecting all egos - */ -#define ID_REST_STATE_INIT 0 - -/** - * Done collecting egos - */ -#define ID_REST_STATE_POST_INIT 1 - -/** - * OIDC grant_type key - */ -#define OIDC_GRANT_TYPE_KEY "grant_type" - -/** - * OIDC grant_type key - */ -#define OIDC_GRANT_TYPE_VALUE "authorization_code" - -/** - * OIDC code key - */ -#define OIDC_CODE_KEY "code" - -/** - * OIDC response_type key - */ -#define OIDC_RESPONSE_TYPE_KEY "response_type" - -/** - * OIDC client_id key - */ -#define OIDC_CLIENT_ID_KEY "client_id" - -/** - * OIDC scope key - */ -#define OIDC_SCOPE_KEY "scope" - -/** - * OIDC redirect_uri key - */ -#define OIDC_REDIRECT_URI_KEY "redirect_uri" - -/** - * OIDC state key - */ -#define OIDC_STATE_KEY "state" - -/** - * OIDC nonce key - */ -#define OIDC_NONCE_KEY "nonce" - -/** - * OIDC cookie header key - */ -#define OIDC_COOKIE_HEADER_KEY "cookie" - -/** - * OIDC cookie header information key - */ -#define OIDC_AUTHORIZATION_HEADER_KEY "authorization" - -/** - * OIDC cookie header information key - */ -#define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity=" - -/** - * OIDC expected response_type while authorizing - */ -#define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code" - -/** - * OIDC expected scope part while authorizing - */ -#define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid" - -/** - * OIDC ignored parameter array - */ -static char* OIDC_ignored_parameter_array [] = -{ - "display", - "prompt", - "ui_locales", - "response_mode", - "id_token_hint", - "login_hint", - "acr_values" -}; - -/** - * OIDC authorized identities and times hashmap - */ -struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time; - -/** - * OIDC authorized identities and times hashmap - */ -struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants; - -/** - * OIDC ticket/code use only once - */ -struct GNUNET_CONTAINER_MultiHashMap *OIDC_ticket_once; - -/** - * OIDC access_token to ticket and ego - */ -struct GNUNET_CONTAINER_MultiHashMap *OIDC_interpret_access_token; - -/** - * The configuration handle - */ -const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * HTTP methods allows for this plugin - */ -static char* allow_methods; - -/** - * @brief struct returned by the initialization function of the plugin - */ -struct Plugin -{ - const struct GNUNET_CONFIGURATION_Handle *cfg; -}; - -/** - * OIDC needed variables - */ -struct OIDC_Variables -{ - /** - * The RP client public key - */ - struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey; - - /** - * The OIDC client id of the RP - */ - char *client_id; - - /** - * The OIDC redirect uri - */ - char *redirect_uri; - - /** - * The list of oidc scopes - */ - char *scope; - - /** - * The OIDC state - */ - char *state; - - /** - * The OIDC nonce - */ - char *nonce; - - /** - * The OIDC response type - */ - char *response_type; - - /** - * The identity chosen by the user to login - */ - char *login_identity; - - /** - * The response JSON - */ - json_t *response; - -}; - -/** - * The ego list - */ -struct EgoEntry -{ - /** - * DLL - */ - struct EgoEntry *next; - - /** - * DLL - */ - struct EgoEntry *prev; - - /** - * Ego Identifier - */ - char *identifier; - - /** - * Public key string - */ - char *keystring; - - /** - * The Ego - */ - struct GNUNET_IDENTITY_Ego *ego; -}; - - -struct RequestHandle -{ - /** - * Ego list - */ - struct EgoEntry *ego_head; - - /** - * Ego list - */ - struct EgoEntry *ego_tail; - - /** - * Selected ego - */ - struct EgoEntry *ego_entry; - - /** - * Pointer to ego private key - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; - - /** - * OIDC variables - */ - struct OIDC_Variables *oidc; - - /** - * The processing state - */ - int state; - - /** - * Handle to Identity service. - */ - struct GNUNET_IDENTITY_Handle *identity_handle; - - /** - * Rest connection - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * GNS handle - */ - struct GNUNET_GNS_Handle *gns_handle; - - /** - * GNS lookup op - */ - struct GNUNET_GNS_LookupRequest *gns_op; - - /** - * Handle to NAMESTORE - */ - struct GNUNET_NAMESTORE_Handle *namestore_handle; - - /** - * Iterator for NAMESTORE - */ - struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it; - - /** - * Attribute claim list - */ - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list; - - /** - * IDENTITY Operation - */ - struct GNUNET_IDENTITY_Operation *op; - - /** - * Identity Provider - */ - struct GNUNET_RECLAIM_Handle *idp; - - /** - * Idp Operation - */ - struct GNUNET_RECLAIM_Operation *idp_op; - - /** - * Attribute iterator - */ - struct GNUNET_RECLAIM_AttributeIterator *attr_it; - - /** - * Ticket iterator - */ - struct GNUNET_RECLAIM_TicketIterator *ticket_it; - - /** - * A ticket - */ - struct GNUNET_RECLAIM_Ticket ticket; - - /** - * Desired timeout for the lookup (default is no timeout). - */ - struct GNUNET_TIME_Relative timeout; - - /** - * ID of a task associated with the resolution process. - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * The url - */ - char *url; - - /** - * The tld for redirect - */ - char *tld; - - /** - * The redirect prefix - */ - char *redirect_prefix; - - /** - * The redirect suffix - */ - char *redirect_suffix; - - /** - * Error response message - */ - char *emsg; - - /** - * Error response description - */ - char *edesc; - - /** - * Reponse code - */ - int response_code; - - /** - * Response object - */ - struct GNUNET_JSONAPI_Document *resp_object; - -}; - -/** - * Cleanup lookup handle - * @param handle Handle to clean up - */ -static void -cleanup_handle (struct RequestHandle *handle) -{ - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry; - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp; - struct EgoEntry *ego_entry; - struct EgoEntry *ego_tmp; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Cleaning up\n"); - if (NULL != handle->resp_object) - GNUNET_JSONAPI_document_delete (handle->resp_object); - if (NULL != handle->timeout_task) - GNUNET_SCHEDULER_cancel (handle->timeout_task); - if (NULL != handle->identity_handle) - GNUNET_IDENTITY_disconnect (handle->identity_handle); - if (NULL != handle->attr_it) - GNUNET_RECLAIM_get_attributes_stop (handle->attr_it); - if (NULL != handle->ticket_it) - GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it); - if (NULL != handle->idp) - GNUNET_RECLAIM_disconnect (handle->idp); - if (NULL != handle->url) - GNUNET_free (handle->url); - if (NULL != handle->tld) - GNUNET_free (handle->tld); - if (NULL != handle->redirect_prefix) - GNUNET_free (handle->redirect_prefix); - if (NULL != handle->redirect_suffix) - GNUNET_free (handle->redirect_suffix); - if (NULL != handle->emsg) - GNUNET_free (handle->emsg); - if (NULL != handle->edesc) - GNUNET_free (handle->edesc); - if (NULL != handle->gns_op) - GNUNET_GNS_lookup_cancel (handle->gns_op); - if (NULL != handle->gns_handle) - GNUNET_GNS_disconnect (handle->gns_handle); - - if (NULL != handle->namestore_handle) - GNUNET_NAMESTORE_disconnect (handle->namestore_handle); - if (NULL != handle->oidc) - { - if (NULL != handle->oidc->client_id) - GNUNET_free(handle->oidc->client_id); - if (NULL != handle->oidc->login_identity) - GNUNET_free(handle->oidc->login_identity); - if (NULL != handle->oidc->nonce) - GNUNET_free(handle->oidc->nonce); - if (NULL != handle->oidc->redirect_uri) - GNUNET_free(handle->oidc->redirect_uri); - if (NULL != handle->oidc->response_type) - GNUNET_free(handle->oidc->response_type); - if (NULL != handle->oidc->scope) - GNUNET_free(handle->oidc->scope); - if (NULL != handle->oidc->state) - GNUNET_free(handle->oidc->state); - if (NULL != handle->oidc->response) - json_decref(handle->oidc->response); - GNUNET_free(handle->oidc); - } - if ( NULL != handle->attr_list ) - { - for (claim_entry = handle->attr_list->list_head; - NULL != claim_entry;) - { - claim_tmp = claim_entry; - claim_entry = claim_entry->next; - GNUNET_free(claim_tmp->claim); - GNUNET_free(claim_tmp); - } - GNUNET_free (handle->attr_list); - } - for (ego_entry = handle->ego_head; - NULL != ego_entry;) - { - ego_tmp = ego_entry; - ego_entry = ego_entry->next; - GNUNET_free (ego_tmp->identifier); - GNUNET_free (ego_tmp->keystring); - GNUNET_free (ego_tmp); - } - if (NULL != handle->attr_it) - { - GNUNET_free(handle->attr_it); - } - GNUNET_free (handle); -} - -static void -cleanup_handle_delayed (void *cls) -{ - cleanup_handle (cls); -} - - -/** - * Task run on error, sends error message. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char *json_error; - - GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}", - handle->emsg, - (NULL != handle->edesc) ? handle->edesc : "", - (NULL != handle->oidc->state) ? ", \"state\":\"" : "", - (NULL != handle->oidc->state) ? handle->oidc->state : "", - (NULL != handle->oidc->state) ? "\"" : ""); - if ( 0 == handle->response_code ) - { - handle->response_code = MHD_HTTP_BAD_REQUEST; - } - resp = GNUNET_REST_create_response (json_error); - if (MHD_HTTP_UNAUTHORIZED == handle->response_code) - { - MHD_add_response_header(resp, "WWW-Authenticate", "Basic"); - } - MHD_add_response_header (resp, "Content-Type", "application/json"); - handle->proc (handle->proc_cls, resp, handle->response_code); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); - GNUNET_free (json_error); -} - - -/** - * Task run on error in userinfo endpoint, sends error header. Cleans up - * everything - * - * @param cls the `struct RequestHandle` - */ -static void -do_userinfo_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char *error; - - GNUNET_asprintf (&error, "error=\"%s\", error_description=\"%s\"", - handle->emsg, - (NULL != handle->edesc) ? handle->edesc : ""); - resp = GNUNET_REST_create_response (""); - MHD_add_response_header(resp, "WWW-Authenticate", error); - handle->proc (handle->proc_cls, resp, handle->response_code); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); - GNUNET_free (error); -} - - -/** - * Task run on error, sends error message and redirects. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_redirect_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char* redirect; - GNUNET_asprintf (&redirect, - "%s?error=%s&error_description=%s%s%s", - handle->oidc->redirect_uri, handle->emsg, handle->edesc, - (NULL != handle->oidc->state) ? "&state=" : "", - (NULL != handle->oidc->state) ? handle->oidc->state : ""); - resp = GNUNET_REST_create_response (""); - MHD_add_response_header (resp, "Location", redirect); - handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); - GNUNET_free (redirect); -} - -/** - * Task run on timeout, sends error message. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_timeout (void *cls) -{ - struct RequestHandle *handle = cls; - - handle->timeout_task = NULL; - do_error (handle); -} - -/** - * Return attributes for claim - * - * @param cls the request handle - */ -static void -return_userinfo_response (void *cls) -{ - char* result_str; - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - result_str = json_dumps (handle->oidc->response, 0); - - resp = GNUNET_REST_create_response (result_str); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free (result_str); - cleanup_handle (handle); -} - -/** - * Returns base64 encoded string without padding - * - * @param string the string to encode - * @return base64 encoded string - */ -static char* -base_64_encode(const char *s) -{ - char *enc; - char *tmp; - - GNUNET_STRINGS_base64_encode(s, strlen(s), &enc); - tmp = strrchr (enc, '='); - *tmp = '\0'; - return enc; -} - -/** - * Respond to OPTIONS request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -options_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - //For now, independent of path return all options - resp = GNUNET_REST_create_response (NULL); - MHD_add_response_header (resp, - "Access-Control-Allow-Methods", - allow_methods); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - cleanup_handle (handle); - return; -} - -/** - * Interprets cookie header and pass its identity keystring to handle - */ -static void -cookie_identity_interpretation (struct RequestHandle *handle) -{ - struct GNUNET_HashCode cache_key; - char *cookies; - struct GNUNET_TIME_Absolute current_time, *relog_time; - char delimiter[] = "; "; - - //gets identity of login try with cookie - GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY), - &cache_key); - if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map, - &cache_key) ) - { - //splits cookies and find 'Identity' cookie - cookies = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key); - handle->oidc->login_identity = strtok(cookies, delimiter); - - while ( NULL != handle->oidc->login_identity ) - { - if ( NULL != strstr (handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY) ) - { - break; - } - handle->oidc->login_identity = strtok (NULL, delimiter); - } - GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen (handle->oidc->login_identity), - &cache_key); - if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, &cache_key) ) - { - relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time, - &cache_key); - current_time = GNUNET_TIME_absolute_get (); - // 30 min after old login -> redirect to login - if ( current_time.abs_value_us <= relog_time->abs_value_us ) - { - handle->oidc->login_identity = strtok(handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY); - handle->oidc->login_identity = GNUNET_strdup(handle->oidc->login_identity); - } else { - handle->oidc->login_identity = NULL; - } - } - else - { - handle->oidc->login_identity = NULL; - } - } -} - -/** - * Redirects to login page stored in configuration file - */ -static void -login_redirection(void *cls) -{ - char *login_base_url; - char *new_redirect; - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - if ( GNUNET_OK - == GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin", - "address", &login_base_url) ) - { - GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s", - login_base_url, - OIDC_RESPONSE_TYPE_KEY, - handle->oidc->response_type, - OIDC_CLIENT_ID_KEY, - handle->oidc->client_id, - OIDC_REDIRECT_URI_KEY, - handle->oidc->redirect_uri, - OIDC_SCOPE_KEY, - handle->oidc->scope, - OIDC_STATE_KEY, - (NULL != handle->oidc->state) ? handle->oidc->state : "", - OIDC_NONCE_KEY, - (NULL != handle->oidc->nonce) ? handle->oidc->nonce : ""); - resp = GNUNET_REST_create_response (""); - MHD_add_response_header (resp, "Location", new_redirect); - GNUNET_free(login_base_url); - } - else - { - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup ("gnunet configuration failed"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); - GNUNET_free(new_redirect); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); -} - -/** - * Does internal server error when iteration failed. - */ -static void -oidc_iteration_error (void *cls) -{ - struct RequestHandle *handle = cls; - handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); -} - -static void -get_client_name_result (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, - const char *label, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char *ticket_str; - char *redirect_uri; - char *code_json_string; - char *code_base64_final_string; - - ticket_str = GNUNET_STRINGS_data_to_string_alloc (&handle->ticket, - sizeof (struct GNUNET_RECLAIM_Ticket)); - //TODO change if more attributes are needed (see max_age) - code_json_string = OIDC_build_authz_code (&handle->priv_key, - &handle->ticket, - handle->oidc->nonce); - code_base64_final_string = base_64_encode(code_json_string); - GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s", - handle->redirect_prefix, - handle->tld, - handle->redirect_suffix, - handle->oidc->response_type, - code_base64_final_string, handle->oidc->state); - resp = GNUNET_REST_create_response (""); - MHD_add_response_header (resp, "Location", redirect_uri); - handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); - GNUNET_free (redirect_uri); - GNUNET_free (ticket_str); - GNUNET_free (code_json_string); - GNUNET_free (code_base64_final_string); - return; - -} - - -static void -get_client_name_error (void *cls) -{ - struct RequestHandle *handle = cls; - - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup("Server cannot generate ticket, no name found for client."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); -} - - -static void -lookup_redirect_uri_result (void *cls, - uint32_t rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct RequestHandle *handle = cls; - char *tmp; - char *tmp_key_str; - char *pos; - struct GNUNET_CRYPTO_EcdsaPublicKey redirect_zone; - - handle->gns_op = NULL; - if (0 == rd_count) - { - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup("Server cannot generate ticket, redirect uri not found."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - for (int i = 0; i < rd_count; i++) - { - if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type) - continue; - if (0 != strcmp (rd[i].data, - handle->oidc->redirect_uri)) - continue; - tmp = GNUNET_strdup (rd[i].data); - pos = strrchr (tmp, - (unsigned char) '.'); - *pos = '\0'; - handle->redirect_prefix = GNUNET_strdup (tmp); - tmp_key_str = pos + 1; - pos = strchr (tmp_key_str, - (unsigned char) '/'); - *pos = '\0'; - handle->redirect_suffix = GNUNET_strdup (pos + 1); - - GNUNET_STRINGS_string_to_data (tmp_key_str, - strlen (tmp_key_str), - &redirect_zone, - sizeof (redirect_zone)); - - GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle, - &handle->priv_key, - &redirect_zone, - &get_client_name_error, - handle, - &get_client_name_result, - handle); - GNUNET_free (tmp); - return; - } - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup("Server cannot generate ticket, redirect uri not found."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); -} - -/** - * Issues ticket and redirects to relying party with the authorization code as - * parameter. Otherwise redirects with error - */ -static void -oidc_ticket_issue_cb (void* cls, - const struct GNUNET_RECLAIM_Ticket *ticket) -{ - struct RequestHandle *handle = cls; - - handle->idp_op = NULL; - handle->ticket = *ticket; - if (NULL == ticket) - { - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup("Server cannot generate ticket."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - handle->gns_op = GNUNET_GNS_lookup (handle->gns_handle, - "+", - &handle->oidc->client_pkey, - GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT, - GNUNET_GNS_LO_DEFAULT, - &lookup_redirect_uri_result, - handle); - -} - -static void -oidc_collect_finished_cb (void *cls) -{ - struct RequestHandle *handle = cls; - handle->attr_it = NULL; - handle->ticket_it = NULL; - if (NULL == handle->attr_list->list_head) - { - handle->emsg = GNUNET_strdup("invalid_scope"); - handle->edesc = GNUNET_strdup("The requested scope is not available."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp, - &handle->priv_key, - &handle->oidc->client_pkey, - handle->attr_list, - &oidc_ticket_issue_cb, - handle); -} - - -/** - * Collects all attributes for an ego if in scope parameter - */ -static void -oidc_attr_collect (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) -{ - struct RequestHandle *handle = cls; - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; - char* scope_variables; - char* scope_variable; - char delimiter[]=" "; - - if ( (NULL == attr->name) || (NULL == attr->data) ) - { - GNUNET_RECLAIM_get_attributes_next (handle->attr_it); - return; - } - - scope_variables = GNUNET_strdup(handle->oidc->scope); - scope_variable = strtok (scope_variables, delimiter); - while (NULL != scope_variable) - { - if ( 0 == strcmp (attr->name, scope_variable) ) - { - break; - } - scope_variable = strtok (NULL, delimiter); - } - if ( NULL == scope_variable ) - { - GNUNET_RECLAIM_get_attributes_next (handle->attr_it); - GNUNET_free(scope_variables); - return; - } - GNUNET_free(scope_variables); - - le = GNUNET_new(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); - le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name, attr->type, - attr->data, attr->data_size); - GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head, - handle->attr_list->list_tail, le); - GNUNET_RECLAIM_get_attributes_next (handle->attr_it); -} - - -/** - * Checks time and cookie and redirects accordingly - */ -static void -login_check (void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_TIME_Absolute current_time, *relog_time; - struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey; - struct GNUNET_HashCode cache_key; - char *identity_cookie; - - GNUNET_asprintf (&identity_cookie, "Identity=%s", handle->oidc->login_identity); - GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key); - GNUNET_free(identity_cookie); - //No login time for identity -> redirect to login - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, - &cache_key) ) - { - relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time, - &cache_key); - current_time = GNUNET_TIME_absolute_get (); - // 30 min after old login -> redirect to login - if ( current_time.abs_value_us <= relog_time->abs_value_us ) - { - if ( GNUNET_OK - != GNUNET_CRYPTO_ecdsa_public_key_from_string ( - handle->oidc->login_identity, - strlen (handle->oidc->login_identity), &pubkey) ) - { - handle->emsg = GNUNET_strdup("invalid_cookie"); - handle->edesc = GNUNET_strdup( - "The cookie of a login identity is not valid"); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - // iterate over egos and compare their public key - for (handle->ego_entry = handle->ego_head; - NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next) - { - GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey); - if ( 0 - == memcmp (&ego_pkey, &pubkey, - sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) - { - handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key ( - handle->ego_entry->ego); - handle->resp_object = GNUNET_JSONAPI_document_new (); - handle->idp = GNUNET_RECLAIM_connect (cfg); - handle->attr_list = GNUNET_new( - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); - handle->attr_it = GNUNET_RECLAIM_get_attributes_start ( - handle->idp, &handle->priv_key, &oidc_iteration_error, handle, - &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle); - return; - } - } - //handle->emsg = GNUNET_strdup("invalid_cookie"); - //handle->edesc = GNUNET_strdup( - // "The cookie of the login identity is not valid"); - //GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - GNUNET_SCHEDULER_add_now (&login_redirection,handle); - return; - } - } -} - -/** - * Iteration over all results finished, build final - * response. - * - * @param cls the `struct RequestHandle` - */ -static void -build_authz_response (void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_HashCode cache_key; - - char *expected_scope; - char delimiter[]=" "; - int number_of_ignored_parameter, iterator; - - - // REQUIRED value: redirect_uri - GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY), - &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->emsg=GNUNET_strdup("invalid_request"); - handle->edesc=GNUNET_strdup("missing parameter redirect_uri"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->oidc->redirect_uri = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key)); - - // REQUIRED value: response_type - GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY), - &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->emsg=GNUNET_strdup("invalid_request"); - handle->edesc=GNUNET_strdup("missing parameter response_type"); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key); - handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type); - - // REQUIRED value: scope - GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->emsg=GNUNET_strdup("invalid_request"); - handle->edesc=GNUNET_strdup("missing parameter scope"); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key); - handle->oidc->scope = GNUNET_strdup(handle->oidc->scope); - - //OPTIONAL value: nonce - GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key); - if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key); - handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce); - } - - //TODO check other values if needed - number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *); - for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ ) - { - GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator], - strlen(OIDC_ignored_parameter_array[iterator]), - &cache_key); - if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map, - &cache_key)) - { - handle->emsg=GNUNET_strdup("access_denied"); - GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s", - OIDC_ignored_parameter_array[iterator]); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - } - - // Checks if response_type is 'code' - if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) ) - { - handle->emsg=GNUNET_strdup("unsupported_response_type"); - handle->edesc=GNUNET_strdup("The authorization server does not support " - "obtaining this authorization code."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - - // Checks if scope contains 'openid' - expected_scope = GNUNET_strdup(handle->oidc->scope); - char* test; - test = strtok (expected_scope, delimiter); - while (NULL != test) - { - if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) ) - { - break; - } - test = strtok (NULL, delimiter); - } - if (NULL == test) - { - handle->emsg = GNUNET_strdup("invalid_scope"); - handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or " - "malformed."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - GNUNET_free(expected_scope); - return; - } - - GNUNET_free(expected_scope); - - if( NULL != handle->oidc->login_identity ) - { - GNUNET_SCHEDULER_add_now(&login_check,handle); - return; - } - - GNUNET_SCHEDULER_add_now(&login_redirection,handle); -} - -/** - * Responds to authorization GET and url-encoded POST request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_HashCode cache_key; - struct EgoEntry *tmp_ego; - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; - struct GNUNET_CRYPTO_EcdsaPublicKey pkey; - - cookie_identity_interpretation(handle); - - //RECOMMENDED value: state - REQUIRED for answers - GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key); - if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key); - handle->oidc->state = GNUNET_strdup (handle->oidc->state); - } - - // REQUIRED value: client_id - GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY), - &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->emsg=GNUNET_strdup("invalid_request"); - handle->edesc=GNUNET_strdup("missing parameter client_id"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->oidc->client_id = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key)); - - if ( GNUNET_OK - != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id, - strlen (handle->oidc->client_id), - &handle->oidc->client_pkey) ) - { - handle->emsg = GNUNET_strdup("unauthorized_client"); - handle->edesc = GNUNET_strdup("The client is not authorized to request an " - "authorization code using this method."); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - - if ( NULL == handle->ego_head ) - { - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup ("Egos are missing"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - handle->ego_entry = handle->ego_head; - handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego); - //If we know this identity, translated the corresponding TLD - //TODO: We might want to have a reverse lookup functionality for TLDs? - for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next) - { - priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego); - GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, - &pkey); - if ( 0 == memcmp (&pkey, &handle->oidc->client_pkey, - sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) - { - handle->tld = GNUNET_strdup (tmp_ego->identifier); - handle->ego_entry = handle->ego_tail; - } - } - GNUNET_SCHEDULER_add_now (&build_authz_response, handle); -} - -/** - * Combines an identity with a login time and responds OK to login request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -login_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct MHD_Response *resp = GNUNET_REST_create_response (""); - struct RequestHandle *handle = cls; - struct GNUNET_HashCode cache_key; - struct GNUNET_TIME_Absolute *current_time; - struct GNUNET_TIME_Absolute *last_time; - char* cookie; - json_t *root; - json_error_t error; - json_t *identity; - char term_data[handle->rest_handle->data_size+1]; - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, handle->rest_handle->data, handle->rest_handle->data_size); - root = json_loads (term_data, JSON_DECODE_ANY, &error); - identity = json_object_get (root, "identity"); - if ( json_is_string(identity) ) - { - GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity)); - MHD_add_response_header (resp, "Set-Cookie", cookie); - MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST"); - GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key); - - current_time = GNUNET_new(struct GNUNET_TIME_Absolute); - *current_time = GNUNET_TIME_relative_to_absolute ( - GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (), - 5)); - last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key); - if (NULL != last_time) - { - GNUNET_free(last_time); - } - GNUNET_CONTAINER_multihashmap_put ( - OIDC_identity_login_time, &cache_key, current_time, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); - - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free(cookie); - } - else - { - handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST); - } - json_decref (root); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); - return; -} - -static int -check_authorization (struct RequestHandle *handle, - struct GNUNET_CRYPTO_EcdsaPublicKey *cid) -{ - struct GNUNET_HashCode cache_key; - char *authorization; - char *credentials; - char *basic_authorization; - char *client_id; - char *pass; - char *expected_pass; - int client_exists = GNUNET_NO; - - GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, - strlen (OIDC_AUTHORIZATION_HEADER_KEY), - &cache_key); - if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map, - &cache_key) ) - { - handle->emsg=GNUNET_strdup("invalid_client"); - handle->edesc=GNUNET_strdup("missing authorization"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - return GNUNET_SYSERR; - } - authorization = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map, - &cache_key); - - //split header in "Basic" and [content] - credentials = strtok (authorization, " "); - if (0 != strcmp ("Basic", credentials)) - { - handle->emsg=GNUNET_strdup("invalid_client"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - return GNUNET_SYSERR; - } - credentials = strtok(NULL, " "); - if (NULL == credentials) - { - handle->emsg=GNUNET_strdup("invalid_client"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - return GNUNET_SYSERR; - } - GNUNET_STRINGS_base64_decode (credentials, - strlen (credentials), - (void**)&basic_authorization); - - if ( NULL == basic_authorization ) - { - handle->emsg=GNUNET_strdup("invalid_client"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - return GNUNET_SYSERR; - } - client_id = strtok (basic_authorization, ":"); - if ( NULL == client_id ) - { - GNUNET_free_non_null(basic_authorization); - handle->emsg=GNUNET_strdup("invalid_client"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - return GNUNET_SYSERR; - } - pass = strtok (NULL, ":"); - if (NULL == pass) - { - GNUNET_free_non_null(basic_authorization); - handle->emsg=GNUNET_strdup("invalid_client"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - return GNUNET_SYSERR; - } - - //check client password - if ( GNUNET_OK - == GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin", - "psw", &expected_pass) ) - { - if (0 != strcmp (expected_pass, pass)) - { - GNUNET_free_non_null(basic_authorization); - GNUNET_free(expected_pass); - handle->emsg=GNUNET_strdup("invalid_client"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - return GNUNET_SYSERR; - } - GNUNET_free(expected_pass); - } - else - { - GNUNET_free_non_null(basic_authorization); - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup ("gnunet configuration failed"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - return GNUNET_SYSERR; - } - - //check client_id - for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; ) - { - if ( 0 == strcmp(handle->ego_entry->keystring, client_id)) - { - client_exists = GNUNET_YES; - break; - } - handle->ego_entry = handle->ego_entry->next; - } - if (GNUNET_NO == client_exists) - { - GNUNET_free_non_null(basic_authorization); - handle->emsg=GNUNET_strdup("invalid_client"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - return GNUNET_SYSERR; - } - GNUNET_STRINGS_string_to_data (client_id, - strlen(client_id), - cid, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - - GNUNET_free (basic_authorization); - return GNUNET_OK; -} - -static int -ego_exists (struct RequestHandle *handle, - struct GNUNET_CRYPTO_EcdsaPublicKey *test_key) -{ - struct EgoEntry *ego_entry; - struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; - - for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) - { - GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key); - if (0 == memcmp (&pub_key, - test_key, - sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) - { - break; - } - } - if (NULL == ego_entry) - return GNUNET_NO; - return GNUNET_YES; -} - -static void -store_ticket_reference (const struct RequestHandle *handle, - const char* access_token, - const struct GNUNET_RECLAIM_Ticket *ticket, - const struct GNUNET_CRYPTO_EcdsaPublicKey *cid) -{ - struct GNUNET_HashCode cache_key; - char *id_ticket_combination; - char *ticket_string; - char *client_id; - - GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key); - client_id = GNUNET_STRINGS_data_to_string_alloc (cid, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - ticket_string = GNUNET_STRINGS_data_to_string_alloc (ticket, - sizeof (struct GNUNET_RECLAIM_Ticket)); - GNUNET_asprintf(&id_ticket_combination, - "%s;%s", - client_id, - ticket_string); - GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token, - &cache_key, - id_ticket_combination, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); - - GNUNET_free (client_id); - GNUNET_free (ticket_string); -} - -/** - * Responds to token url-encoded POST request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_TIME_Relative expiration_time; - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *cl; - struct GNUNET_RECLAIM_Ticket *ticket; - struct GNUNET_CRYPTO_EcdsaPublicKey cid; - struct GNUNET_HashCode cache_key; - struct MHD_Response *resp; - char *grant_type; - char *code; - char *json_response; - char *id_token; - char *access_token; - char *jwt_secret; - char *nonce; - int i = 1; - - /* - * Check Authorization - */ - if (GNUNET_SYSERR == check_authorization (handle, - &cid)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "OIDC authorization for token endpoint failed\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - /* - * Check parameter - */ - - //TODO Do not allow multiple equal parameter names - //REQUIRED grant_type - GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), &cache_key); - if (GNUNET_NO == - GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("missing parameter grant_type"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - grant_type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, - &cache_key); - - //REQUIRED code - GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key); - if (GNUNET_NO == - GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("missing parameter code"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - code = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, - &cache_key); - - //REQUIRED redirect_uri - GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY), - &cache_key); - if (GNUNET_NO == - GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key) ) - { - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("missing parameter redirect_uri"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - //Check parameter grant_type == "authorization_code" - if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type)) - { - handle->emsg=GNUNET_strdup("unsupported_grant_type"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - GNUNET_CRYPTO_hash (code, strlen (code), &cache_key); - if (GNUNET_SYSERR == - GNUNET_CONTAINER_multihashmap_put (OIDC_ticket_once, - &cache_key, - &i, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) ) - { - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("Cannot use the same code more than once"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - //decode code - if(GNUNET_OK != OIDC_parse_authz_code (&cid, - code, - &ticket, - &nonce)) - { - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("invalid code"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - //create jwt - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time(cfg, - "reclaim-rest-plugin", - "expiration_time", - &expiration_time)) - { - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup ("gnunet configuration failed"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - GNUNET_free(ticket); - return; - } - - - //TODO OPTIONAL acr,amr,azp - if (GNUNET_NO == ego_exists (handle, - &ticket->audience)) - { - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("invalid code..."); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - GNUNET_free(ticket); - } - if ( GNUNET_OK - != GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin", - "jwt_secret", &jwt_secret) ) - { - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("No signing secret configured!"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - GNUNET_free(ticket); - return; - } - //TODO We should collect the attributes here. cl always empty - cl = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); - id_token = OIDC_id_token_new (&ticket->audience, - &ticket->identity, - cl, - &expiration_time, - (NULL != nonce) ? nonce : NULL, - jwt_secret); - access_token = OIDC_access_token_new (); - OIDC_build_token_response (access_token, - id_token, - &expiration_time, - &json_response); - - store_ticket_reference (handle, - access_token, - ticket, - &cid); - resp = GNUNET_REST_create_response (json_response); - MHD_add_response_header (resp, "Cache-Control", "no-store"); - MHD_add_response_header (resp, "Pragma", "no-cache"); - MHD_add_response_header (resp, "Content-Type", "application/json"); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_RECLAIM_ATTRIBUTE_list_destroy(cl); - GNUNET_free(access_token); - GNUNET_free(json_response); - GNUNET_free(ticket); - GNUNET_free(id_token); - GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle); -} - -/** - * Collects claims and stores them in handle - */ -static void -consume_ticket (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) -{ - struct RequestHandle *handle = cls; - char *tmp_value; - json_t *value; - - if (NULL == identity) - { - GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle); - return; - } - - tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, - attr->data, - attr->data_size); - - value = json_string (tmp_value); - - - json_object_set_new (handle->oidc->response, - attr->name, - value); - GNUNET_free (tmp_value); -} - -/** - * Responds to userinfo GET and url-encoded POST request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, void *cls) -{ - //TODO expiration time - struct RequestHandle *handle = cls; - char delimiter[] = " "; - char delimiter_db[] = ";"; - struct GNUNET_HashCode cache_key; - char *authorization, *authorization_type, *authorization_access_token; - char *client_ticket, *client, *ticket_str; - struct GNUNET_RECLAIM_Ticket *ticket; - - GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, - strlen (OIDC_AUTHORIZATION_HEADER_KEY), - &cache_key); - if ( GNUNET_NO - == GNUNET_CONTAINER_multihashmap_contains ( - handle->rest_handle->header_param_map, &cache_key) ) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("No Access Token"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - return; - } - authorization = GNUNET_CONTAINER_multihashmap_get ( - handle->rest_handle->header_param_map, &cache_key); - - //split header in "Bearer" and access_token - authorization = GNUNET_strdup(authorization); - authorization_type = strtok (authorization, delimiter); - if ( 0 != strcmp ("Bearer", authorization_type) ) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("No Access Token"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - return; - } - authorization_access_token = strtok (NULL, delimiter); - if ( NULL == authorization_access_token ) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("No Access Token"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - return; - } - - GNUNET_CRYPTO_hash (authorization_access_token, - strlen (authorization_access_token), - &cache_key); - if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_interpret_access_token, - &cache_key) ) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("The Access Token expired"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - return; - } - - client_ticket = GNUNET_CONTAINER_multihashmap_get(OIDC_interpret_access_token, - &cache_key); - client_ticket = GNUNET_strdup(client_ticket); - client = strtok(client_ticket,delimiter_db); - if (NULL == client) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("The Access Token expired"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - GNUNET_free(client_ticket); - return; - } - handle->ego_entry = handle->ego_head; - for(; NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next) - { - if (0 == strcmp(handle->ego_entry->keystring,client)) - { - break; - } - } - if (NULL == handle->ego_entry) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("The Access Token expired"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - GNUNET_free(client_ticket); - return; - } - ticket_str = strtok(NULL, delimiter_db); - if (NULL == ticket_str) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("The Access Token expired"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - GNUNET_free(client_ticket); - return; - } - ticket = GNUNET_new(struct GNUNET_RECLAIM_Ticket); - if ( GNUNET_OK - != GNUNET_STRINGS_string_to_data (ticket_str, - strlen (ticket_str), - ticket, - sizeof(struct GNUNET_RECLAIM_Ticket))) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("The Access Token expired"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(ticket); - GNUNET_free(authorization); - GNUNET_free(client_ticket); - return; - } - - handle->idp = GNUNET_RECLAIM_connect (cfg); - handle->oidc->response = json_object(); - json_object_set_new( handle->oidc->response, "sub", json_string( handle->ego_entry->keystring)); - handle->idp_op = GNUNET_RECLAIM_ticket_consume ( - handle->idp, - GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego), - ticket, - consume_ticket, - handle); - GNUNET_free(ticket); - GNUNET_free(authorization); - GNUNET_free(client_ticket); - -} - - -/** - * Handle rest request - * - * @param handle the request handle - */ -static void -init_cont (struct RequestHandle *handle) -{ - struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = { - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, //url-encoded - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont}, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint }, - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, - {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, - &options_cont}, - GNUNET_REST_HANDLER_END - }; - - if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, - handlers, - &err, - handle)) - { - handle->response_code = err.error_code; - GNUNET_SCHEDULER_add_now (&do_error, handle); - } -} - -/** - * If listing is enabled, prints information about the egos. - * - * This function is initially called for all egos and then again - * whenever a ego's identifier changes or if it is deleted. At the - * end of the initial pass over all egos, the function is once called - * with 'NULL' for 'ego'. That does NOT mean that the callback won't - * be invoked in the future or that there was an error. - * - * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', - * this function is only called ONCE, and 'NULL' being passed in - * 'ego' does indicate an error (i.e. name is taken or no default - * value is known). If 'ego' is non-NULL and if '*ctx' - * is set in those callbacks, the value WILL be passed to a subsequent - * call to the identity callback of 'GNUNET_IDENTITY_connect' (if - * that one was not NULL). - * - * When an identity is renamed, this function is called with the - * (known) ego but the NEW identifier. - * - * When an identity is deleted, this function is called with the - * (known) ego and "NULL" for the 'identifier'. In this case, - * the 'ego' is henceforth invalid (and the 'ctx' should also be - * cleaned up). - * - * @param cls closure - * @param ego ego handle - * @param ctx context for application to store data for this ego - * (during the lifetime of this process, initially NULL) - * @param identifier identifier assigned by the user for this ego, - * NULL if the user just deleted the ego and it - * must thus no longer be used - */ -static void -list_ego (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *identifier) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct GNUNET_CRYPTO_EcdsaPublicKey pk; - - if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state)) - { - handle->state = ID_REST_STATE_POST_INIT; - init_cont (handle); - return; - } - if (ID_REST_STATE_INIT == handle->state) { - ego_entry = GNUNET_new (struct EgoEntry); - GNUNET_IDENTITY_ego_get_public_key (ego, &pk); - ego_entry->keystring = - GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); - ego_entry->ego = ego; - ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); - return; - } - /* Ego renamed or added */ - if (identifier != NULL) { - for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) { - if (ego_entry->ego == ego) { - /* Rename */ - GNUNET_free (ego_entry->identifier); - ego_entry->identifier = GNUNET_strdup (identifier); - break; - } - } - if (NULL == ego_entry) { - /* Add */ - ego_entry = GNUNET_new (struct EgoEntry); - GNUNET_IDENTITY_ego_get_public_key (ego, &pk); - ego_entry->keystring = - GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); - ego_entry->ego = ego; - ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); - } - } else { - /* Delete */ - for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) { - if (ego_entry->ego == ego) - break; - } - if (NULL != ego_entry) - GNUNET_CONTAINER_DLL_remove(handle->ego_head,handle->ego_tail, ego_entry); - } - -} - -static void -rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) -{ - struct RequestHandle *handle = GNUNET_new (struct RequestHandle); - handle->oidc = GNUNET_new (struct OIDC_Variables); - if ( NULL == OIDC_identity_login_time ) - OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); - if ( NULL == OIDC_identity_grants ) - OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); - if ( NULL == OIDC_ticket_once ) - OIDC_ticket_once = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); - if ( NULL == OIDC_interpret_access_token ) - OIDC_interpret_access_token = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); - handle->response_code = 0; - handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; - handle->proc_cls = proc_cls; - handle->proc = proc; - handle->state = ID_REST_STATE_INIT; - handle->rest_handle = rest_handle; - - handle->url = GNUNET_strdup (rest_handle->url); - if (handle->url[strlen (handle->url)-1] == '/') - handle->url[strlen (handle->url)-1] = '\0'; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connecting...\n"); - handle->identity_handle = GNUNET_IDENTITY_connect (cfg, - &list_ego, - handle); - handle->gns_handle = GNUNET_GNS_connect (cfg); - handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg); - handle->timeout_task = - GNUNET_SCHEDULER_add_delayed (handle->timeout, - &do_timeout, - handle); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connected\n"); -} - -/** - * Entry point for the plugin. - * - * @param cls Config info - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_rest_openid_connect_init (void *cls) -{ - static struct Plugin plugin; - struct GNUNET_REST_Plugin *api; - - cfg = cls; - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof (struct Plugin)); - plugin.cfg = cfg; - api = GNUNET_new (struct GNUNET_REST_Plugin); - api->cls = &plugin; - api->name = GNUNET_REST_API_NS_OIDC; - api->process_request = &rest_identity_process_request; - GNUNET_asprintf (&allow_methods, - "%s, %s, %s, %s, %s", - MHD_HTTP_METHOD_GET, - MHD_HTTP_METHOD_POST, - MHD_HTTP_METHOD_PUT, - MHD_HTTP_METHOD_DELETE, - MHD_HTTP_METHOD_OPTIONS); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _("Identity Provider REST API initialized\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ -void * -libgnunet_plugin_rest_openid_connect_done (void *cls) -{ - struct GNUNET_REST_Plugin *api = cls; - struct Plugin *plugin = api->cls; - plugin->cfg = NULL; - - struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it; - void *value = NULL; - hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create ( - OIDC_identity_login_time); - while (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) - { - if (NULL != value) - GNUNET_free(value); - } - GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time); - hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants); - while (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) - { - if (NULL != value) - GNUNET_free(value); - } - GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants); - hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_ticket_once); - while (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) - { - if (NULL != value) - GNUNET_free(value); - } - GNUNET_CONTAINER_multihashmap_destroy(OIDC_ticket_once); - hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_interpret_access_token); - while (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) - { - if (NULL != value) - GNUNET_free(value); - } - GNUNET_CONTAINER_multihashmap_destroy(OIDC_interpret_access_token); - GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it); - GNUNET_free_non_null (allow_methods); - GNUNET_free (api); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Identity Provider REST plugin is finished\n"); - return NULL; -} - -/* end of plugin_rest_identity_provider.c */ diff --git a/src/reclaim/plugin_rest_reclaim.c b/src/reclaim/plugin_rest_reclaim.c deleted file mode 100644 index 38ffc4ddb..000000000 --- a/src/reclaim/plugin_rest_reclaim.c +++ /dev/null @@ -1,1253 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -/** - * @author Martin Schanzenbach - * @author Philippe Buschmann - * @file reclaim/plugin_rest_reclaim.c - * @brief GNUnet reclaim REST plugin - * - */ - -#include "platform.h" -#include "gnunet_rest_plugin.h" -#include "gnunet_identity_service.h" -#include "gnunet_gns_service.h" -#include "gnunet_gnsrecord_lib.h" -#include "gnunet_namestore_service.h" -#include "gnunet_rest_lib.h" -#include "gnunet_jsonapi_lib.h" -#include "gnunet_jsonapi_util.h" -#include "microhttpd.h" -#include -#include -#include "gnunet_signatures.h" -#include "gnunet_reclaim_attribute_lib.h" -#include "gnunet_reclaim_service.h" - -/** - * REST root namespace - */ -#define GNUNET_REST_API_NS_RECLAIM "/reclaim" - -/** - * Attribute namespace - */ -#define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/reclaim/attributes" - -/** - * Ticket namespace - */ -#define GNUNET_REST_API_NS_IDENTITY_TICKETS "/reclaim/tickets" - -/** - * Revoke namespace - */ -#define GNUNET_REST_API_NS_IDENTITY_REVOKE "/reclaim/revoke" - -/** - * Revoke namespace - */ -#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/reclaim/consume" - -/** - * Attribute key - */ -#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE "attribute" - -/** - * Ticket key - */ -#define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket" - - -/** - * Value key - */ -#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE_VALUE "value" - -/** - * State while collecting all egos - */ -#define ID_REST_STATE_INIT 0 - -/** - * Done collecting egos - */ -#define ID_REST_STATE_POST_INIT 1 - -/** - * The configuration handle - */ -const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * HTTP methods allows for this plugin - */ -static char* allow_methods; - -/** - * @brief struct returned by the initialization function of the plugin - */ -struct Plugin -{ - const struct GNUNET_CONFIGURATION_Handle *cfg; -}; - -/** - * The ego list - */ -struct EgoEntry -{ - /** - * DLL - */ - struct EgoEntry *next; - - /** - * DLL - */ - struct EgoEntry *prev; - - /** - * Ego Identifier - */ - char *identifier; - - /** - * Public key string - */ - char *keystring; - - /** - * The Ego - */ - struct GNUNET_IDENTITY_Ego *ego; -}; - - -struct RequestHandle -{ - /** - * Ego list - */ - struct EgoEntry *ego_head; - - /** - * Ego list - */ - struct EgoEntry *ego_tail; - - /** - * Selected ego - */ - struct EgoEntry *ego_entry; - - /** - * Pointer to ego private key - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; - - /** - * The processing state - */ - int state; - - /** - * Handle to Identity service. - */ - struct GNUNET_IDENTITY_Handle *identity_handle; - - /** - * Rest connection - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * Handle to NAMESTORE - */ - struct GNUNET_NAMESTORE_Handle *namestore_handle; - - /** - * Iterator for NAMESTORE - */ - struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it; - - /** - * Attribute claim list - */ - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list; - - /** - * IDENTITY Operation - */ - struct GNUNET_IDENTITY_Operation *op; - - /** - * Identity Provider - */ - struct GNUNET_RECLAIM_Handle *idp; - - /** - * Idp Operation - */ - struct GNUNET_RECLAIM_Operation *idp_op; - - /** - * Attribute iterator - */ - struct GNUNET_RECLAIM_AttributeIterator *attr_it; - - /** - * Ticket iterator - */ - struct GNUNET_RECLAIM_TicketIterator *ticket_it; - - /** - * A ticket - */ - struct GNUNET_RECLAIM_Ticket ticket; - - /** - * Desired timeout for the lookup (default is no timeout). - */ - struct GNUNET_TIME_Relative timeout; - - /** - * ID of a task associated with the resolution process. - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * The url - */ - char *url; - - /** - * Error response message - */ - char *emsg; - - /** - * Reponse code - */ - int response_code; - - /** - * Response object - */ - struct GNUNET_JSONAPI_Document *resp_object; - -}; - -/** - * Cleanup lookup handle - * @param handle Handle to clean up - */ -static void -cleanup_handle (struct RequestHandle *handle) -{ - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry; - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp; - struct EgoEntry *ego_entry; - struct EgoEntry *ego_tmp; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Cleaning up\n"); - if (NULL != handle->resp_object) - GNUNET_JSONAPI_document_delete (handle->resp_object); - if (NULL != handle->timeout_task) - GNUNET_SCHEDULER_cancel (handle->timeout_task); - if (NULL != handle->identity_handle) - GNUNET_IDENTITY_disconnect (handle->identity_handle); - if (NULL != handle->attr_it) - GNUNET_RECLAIM_get_attributes_stop (handle->attr_it); - if (NULL != handle->ticket_it) - GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it); - if (NULL != handle->idp) - GNUNET_RECLAIM_disconnect (handle->idp); - if (NULL != handle->url) - GNUNET_free (handle->url); - if (NULL != handle->emsg) - GNUNET_free (handle->emsg); - if (NULL != handle->namestore_handle) - GNUNET_NAMESTORE_disconnect (handle->namestore_handle); - if ( NULL != handle->attr_list ) - { - for (claim_entry = handle->attr_list->list_head; - NULL != claim_entry;) - { - claim_tmp = claim_entry; - claim_entry = claim_entry->next; - GNUNET_free(claim_tmp->claim); - GNUNET_free(claim_tmp); - } - GNUNET_free (handle->attr_list); - } - for (ego_entry = handle->ego_head; - NULL != ego_entry;) - { - ego_tmp = ego_entry; - ego_entry = ego_entry->next; - GNUNET_free (ego_tmp->identifier); - GNUNET_free (ego_tmp->keystring); - GNUNET_free (ego_tmp); - } - if (NULL != handle->attr_it) - { - GNUNET_free(handle->attr_it); - } - GNUNET_free (handle); -} - -static void -cleanup_handle_delayed (void *cls) -{ - cleanup_handle (cls); -} - - -/** - * Task run on error, sends error message. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char *json_error; - - GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", - handle->emsg); - if ( 0 == handle->response_code ) - { - handle->response_code = MHD_HTTP_BAD_REQUEST; - } - resp = GNUNET_REST_create_response (json_error); - MHD_add_response_header (resp, "Content-Type", "application/json"); - handle->proc (handle->proc_cls, resp, handle->response_code); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); - GNUNET_free (json_error); -} - - -/** - * Task run on timeout, sends error message. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_timeout (void *cls) -{ - struct RequestHandle *handle = cls; - - handle->timeout_task = NULL; - do_error (handle); -} - - -static void -collect_error_cb (void *cls) -{ - struct RequestHandle *handle = cls; - - do_error (handle); -} - -static void -finished_cont (void *cls, - int32_t success, - const char *emsg) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - resp = GNUNET_REST_create_response (emsg); - if (GNUNET_OK != success) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); -} - - -/** - * Return attributes for identity - * - * @param cls the request handle - */ -static void -return_response (void *cls) -{ - char* result_str; - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free (result_str); - cleanup_handle (handle); -} - -static void -collect_finished_cb (void *cls) -{ - struct RequestHandle *handle = cls; - //Done - handle->attr_it = NULL; - handle->ticket_it = NULL; - GNUNET_SCHEDULER_add_now (&return_response, handle); -} - - -/** - * Collect all attributes for an ego - * - */ -static void -ticket_collect (void *cls, - const struct GNUNET_RECLAIM_Ticket *ticket) -{ - struct GNUNET_JSONAPI_Resource *json_resource; - struct RequestHandle *handle = cls; - json_t *value; - char* tmp; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n"); - tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, - sizeof (uint64_t)); - json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET, - tmp); - GNUNET_free (tmp); - GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); - - tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - value = json_string (tmp); - GNUNET_JSONAPI_resource_add_attr (json_resource, - "issuer", - value); - GNUNET_free (tmp); - json_decref (value); - tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - value = json_string (tmp); - GNUNET_JSONAPI_resource_add_attr (json_resource, - "audience", - value); - GNUNET_free (tmp); - json_decref (value); - tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, - sizeof (uint64_t)); - value = json_string (tmp); - GNUNET_JSONAPI_resource_add_attr (json_resource, - "rnd", - value); - GNUNET_free (tmp); - json_decref (value); - GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it); -} - - - -/** - * List tickets for identity request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *identity; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n", - handle->url); - if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= - strlen (handle->url)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1; - - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - if (0 == strcmp (identity, ego_entry->identifier)) - break; - handle->resp_object = GNUNET_JSONAPI_document_new (); - - if (NULL == ego_entry) - { - //Done - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", - identity); - GNUNET_SCHEDULER_add_now (&return_response, handle); - return; - } - priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - handle->idp = GNUNET_RECLAIM_connect (cfg); - handle->ticket_it = GNUNET_RECLAIM_ticket_iteration_start (handle->idp, - priv_key, - &collect_error_cb, - handle, - &ticket_collect, - handle, - &collect_finished_cb, - handle); -} - - -static void -add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; - const char* identity; - const char* name_str; - const char* value_str; - const char* exp_str; - - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct MHD_Response *resp; - struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute; - struct GNUNET_JSONAPI_Document *json_obj; - struct GNUNET_JSONAPI_Resource *json_res; - struct GNUNET_TIME_Relative exp; - char term_data[handle->rest_handle->data_size+1]; - json_t *value_json; - json_t *data_json; - json_t *exp_json; - json_error_t err; - struct GNUNET_JSON_Specification docspec[] = { - GNUNET_JSON_spec_jsonapi_document (&json_obj), - GNUNET_JSON_spec_end() - }; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n", - handle->url); - if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= - strlen (handle->url)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1; - - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - if (0 == strcmp (identity, ego_entry->identifier)) - break; - - if (NULL == ego_entry) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Identity unknown (%s)\n", identity); - GNUNET_JSONAPI_document_delete (json_obj); - return; - } - identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - - if (0 >= handle->rest_handle->data_size) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, - handle->rest_handle->data, - handle->rest_handle->data_size); - data_json = json_loads (term_data, - JSON_DECODE_ANY, - &err); - GNUNET_assert (GNUNET_OK == - GNUNET_JSON_parse (data_json, docspec, - NULL, NULL)); - json_decref (data_json); - if (NULL == json_obj) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse JSONAPI Object from %s\n", - term_data); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Cannot create more than 1 resource! (Got %d)\n", - GNUNET_JSONAPI_document_resource_count (json_obj)); - GNUNET_JSONAPI_document_delete (json_obj); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); - if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, - GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unsupported JSON data type\n"); - GNUNET_JSONAPI_document_delete (json_obj); - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); - cleanup_handle (handle); - return; - } - name_str = GNUNET_JSONAPI_resource_get_id (json_res); - exp_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "exp"); - exp_str = json_string_value (exp_json); - if (NULL == exp_str) { - exp = GNUNET_TIME_UNIT_HOURS; - } else { - if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (exp_str, - &exp)) { - exp = GNUNET_TIME_UNIT_HOURS; - } - } - - value_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "value"); - value_str = json_string_value (value_json); - attribute = GNUNET_RECLAIM_ATTRIBUTE_claim_new (name_str, - GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING, - value_str, - strlen (value_str) + 1); - handle->idp = GNUNET_RECLAIM_connect (cfg); - handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp, - identity_priv, - attribute, - &exp, - &finished_cont, - handle); - GNUNET_free (attribute); - GNUNET_JSONAPI_document_delete (json_obj); -} - - - -/** - * Collect all attributes for an ego - * - */ -static void -attr_collect (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) -{ - struct GNUNET_JSONAPI_Resource *json_resource; - struct RequestHandle *handle = cls; - json_t *value; - char* tmp_value; - - if ((NULL == attr->name) || (NULL == attr->data)) - { - GNUNET_RECLAIM_get_attributes_next (handle->attr_it); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", - attr->name); - json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE, - attr->name); - GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); - - tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, - attr->data, - attr->data_size); - - value = json_string (tmp_value); - - GNUNET_JSONAPI_resource_add_attr (json_resource, - "value", - value); - json_decref (value); - GNUNET_free(tmp_value); - GNUNET_RECLAIM_get_attributes_next (handle->attr_it); -} - - - -/** - * List attributes for identity request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *identity; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n", - handle->url); - if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= - strlen (handle->url)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1; - - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - if (0 == strcmp (identity, ego_entry->identifier)) - break; - handle->resp_object = GNUNET_JSONAPI_document_new (); - - - if (NULL == ego_entry) - { - //Done - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", - identity); - GNUNET_SCHEDULER_add_now (&return_response, handle); - return; - } - priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - handle->idp = GNUNET_RECLAIM_connect (cfg); - handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp, - priv_key, - &collect_error_cb, - handle, - &attr_collect, - handle, - &collect_finished_cb, - handle); -} - - -static void -revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; - const char* identity_str; - const char* audience_str; - const char* rnd_str; - - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct MHD_Response *resp; - struct GNUNET_RECLAIM_Ticket ticket; - struct GNUNET_JSONAPI_Document *json_obj; - struct GNUNET_JSONAPI_Resource *json_res; - struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk; - char term_data[handle->rest_handle->data_size+1]; - json_t *rnd_json; - json_t *identity_json; - json_t *audience_json; - json_t *data_json; - json_error_t err; - struct GNUNET_JSON_Specification docspec[] = { - GNUNET_JSON_spec_jsonapi_document (&json_obj), - GNUNET_JSON_spec_end() - }; - - if (0 >= handle->rest_handle->data_size) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, - handle->rest_handle->data, - handle->rest_handle->data_size); - data_json = json_loads (term_data, - JSON_DECODE_ANY, - &err); - GNUNET_assert (GNUNET_OK == - GNUNET_JSON_parse (data_json, docspec, - NULL, NULL)); - json_decref (data_json); - if (NULL == json_obj) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse JSONAPI Object from %s\n", - term_data); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Cannot create more than 1 resource! (Got %d)\n", - GNUNET_JSONAPI_document_resource_count (json_obj)); - GNUNET_JSONAPI_document_delete (json_obj); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); - if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, - GNUNET_REST_JSONAPI_IDENTITY_TICKET)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unsupported JSON data type\n"); - GNUNET_JSONAPI_document_delete (json_obj); - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); - cleanup_handle (handle); - return; - } - rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "rnd"); - identity_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "issuer"); - audience_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "audience"); - rnd_str = json_string_value (rnd_json); - identity_str = json_string_value (identity_json); - audience_str = json_string_value (audience_json); - - GNUNET_STRINGS_string_to_data (rnd_str, - strlen (rnd_str), - &ticket.rnd, - sizeof (uint64_t)); - GNUNET_STRINGS_string_to_data (identity_str, - strlen (identity_str), - &ticket.identity, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - GNUNET_STRINGS_string_to_data (audience_str, - strlen (audience_str), - &ticket.audience, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - { - GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, - &tmp_pk); - if (0 == memcmp (&ticket.identity, - &tmp_pk, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) - break; - } - if (NULL == ego_entry) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Identity unknown (%s)\n", identity_str); - GNUNET_JSONAPI_document_delete (json_obj); - return; - } - identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - - handle->idp = GNUNET_RECLAIM_connect (cfg); - handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp, - identity_priv, - &ticket, - &finished_cont, - handle); - GNUNET_JSONAPI_document_delete (json_obj); -} - -static void -consume_cont (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) -{ - struct RequestHandle *handle = cls; - struct GNUNET_JSONAPI_Resource *json_resource; - json_t *value; - - if (NULL == identity) - { - GNUNET_SCHEDULER_add_now (&return_response, handle); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", - attr->name); - json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE, - attr->name); - GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); - - value = json_string (attr->data); - GNUNET_JSONAPI_resource_add_attr (json_resource, - "value", - value); - json_decref (value); -} - -static void -consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; - const char* identity_str; - const char* audience_str; - const char* rnd_str; - - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct MHD_Response *resp; - struct GNUNET_RECLAIM_Ticket ticket; - struct GNUNET_JSONAPI_Document *json_obj; - struct GNUNET_JSONAPI_Resource *json_res; - struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk; - char term_data[handle->rest_handle->data_size+1]; - json_t *rnd_json; - json_t *identity_json; - json_t *audience_json; - json_t *data_json; - json_error_t err; - struct GNUNET_JSON_Specification docspec[] = { - GNUNET_JSON_spec_jsonapi_document (&json_obj), - GNUNET_JSON_spec_end() - }; - - if (0 >= handle->rest_handle->data_size) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, - handle->rest_handle->data, - handle->rest_handle->data_size); - data_json = json_loads (term_data, - JSON_DECODE_ANY, - &err); - GNUNET_assert (GNUNET_OK == - GNUNET_JSON_parse (data_json, docspec, - NULL, NULL)); - json_decref (data_json); - if (NULL == json_obj) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse JSONAPI Object from %s\n", - term_data); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Cannot create more than 1 resource! (Got %d)\n", - GNUNET_JSONAPI_document_resource_count (json_obj)); - GNUNET_JSONAPI_document_delete (json_obj); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); - if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, - GNUNET_REST_JSONAPI_IDENTITY_TICKET)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unsupported JSON data type\n"); - GNUNET_JSONAPI_document_delete (json_obj); - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); - cleanup_handle (handle); - return; - } - rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "rnd"); - identity_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "identity"); - audience_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "audience"); - rnd_str = json_string_value (rnd_json); - identity_str = json_string_value (identity_json); - audience_str = json_string_value (audience_json); - - GNUNET_STRINGS_string_to_data (rnd_str, - strlen (rnd_str), - &ticket.rnd, - sizeof (uint64_t)); - GNUNET_STRINGS_string_to_data (identity_str, - strlen (identity_str), - &ticket.identity, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - GNUNET_STRINGS_string_to_data (audience_str, - strlen (audience_str), - &ticket.audience, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - { - GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, - &tmp_pk); - if (0 == memcmp (&ticket.audience, - &tmp_pk, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) - break; - } - if (NULL == ego_entry) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Identity unknown (%s)\n", identity_str); - GNUNET_JSONAPI_document_delete (json_obj); - return; - } - identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - handle->resp_object = GNUNET_JSONAPI_document_new (); - handle->idp = GNUNET_RECLAIM_connect (cfg); - handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp, - identity_priv, - &ticket, - &consume_cont, - handle); - GNUNET_JSONAPI_document_delete (json_obj); -} - - - -/** - * Respond to OPTIONS request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -options_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - //For now, independent of path return all options - resp = GNUNET_REST_create_response (NULL); - MHD_add_response_header (resp, - "Access-Control-Allow-Methods", - allow_methods); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - cleanup_handle (handle); - return; -} - -/** - * Handle rest request - * - * @param handle the request handle - */ -static void -init_cont (struct RequestHandle *handle) -{ - struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = { - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &list_attribute_cont}, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &add_attribute_cont}, - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont}, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont}, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont}, - {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, - &options_cont}, - GNUNET_REST_HANDLER_END - }; - - if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, - handlers, - &err, - handle)) - { - handle->response_code = err.error_code; - GNUNET_SCHEDULER_add_now (&do_error, handle); - } -} - -/** - * If listing is enabled, prints information about the egos. - * - * This function is initially called for all egos and then again - * whenever a ego's identifier changes or if it is deleted. At the - * end of the initial pass over all egos, the function is once called - * with 'NULL' for 'ego'. That does NOT mean that the callback won't - * be invoked in the future or that there was an error. - * - * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', - * this function is only called ONCE, and 'NULL' being passed in - * 'ego' does indicate an error (i.e. name is taken or no default - * value is known). If 'ego' is non-NULL and if '*ctx' - * is set in those callbacks, the value WILL be passed to a subsequent - * call to the identity callback of 'GNUNET_IDENTITY_connect' (if - * that one was not NULL). - * - * When an identity is renamed, this function is called with the - * (known) ego but the NEW identifier. - * - * When an identity is deleted, this function is called with the - * (known) ego and "NULL" for the 'identifier'. In this case, - * the 'ego' is henceforth invalid (and the 'ctx' should also be - * cleaned up). - * - * @param cls closure - * @param ego ego handle - * @param ctx context for application to store data for this ego - * (during the lifetime of this process, initially NULL) - * @param identifier identifier assigned by the user for this ego, - * NULL if the user just deleted the ego and it - * must thus no longer be used - */ -static void -list_ego (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *identifier) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct GNUNET_CRYPTO_EcdsaPublicKey pk; - - if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state)) - { - handle->state = ID_REST_STATE_POST_INIT; - init_cont (handle); - return; - } - if (ID_REST_STATE_INIT == handle->state) { - ego_entry = GNUNET_new (struct EgoEntry); - GNUNET_IDENTITY_ego_get_public_key (ego, &pk); - ego_entry->keystring = - GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); - ego_entry->ego = ego; - ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); - } - -} - -static void -rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) -{ - struct RequestHandle *handle = GNUNET_new (struct RequestHandle); - handle->response_code = 0; - handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; - handle->proc_cls = proc_cls; - handle->proc = proc; - handle->state = ID_REST_STATE_INIT; - handle->rest_handle = rest_handle; - - handle->url = GNUNET_strdup (rest_handle->url); - if (handle->url[strlen (handle->url)-1] == '/') - handle->url[strlen (handle->url)-1] = '\0'; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connecting...\n"); - handle->identity_handle = GNUNET_IDENTITY_connect (cfg, - &list_ego, - handle); - handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg); - handle->timeout_task = - GNUNET_SCHEDULER_add_delayed (handle->timeout, - &do_timeout, - handle); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connected\n"); -} - -/** - * Entry point for the plugin. - * - * @param cls Config info - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_rest_reclaim_init (void *cls) -{ - static struct Plugin plugin; - struct GNUNET_REST_Plugin *api; - - cfg = cls; - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof (struct Plugin)); - plugin.cfg = cfg; - api = GNUNET_new (struct GNUNET_REST_Plugin); - api->cls = &plugin; - api->name = GNUNET_REST_API_NS_RECLAIM; - api->process_request = &rest_identity_process_request; - GNUNET_asprintf (&allow_methods, - "%s, %s, %s, %s, %s", - MHD_HTTP_METHOD_GET, - MHD_HTTP_METHOD_POST, - MHD_HTTP_METHOD_PUT, - MHD_HTTP_METHOD_DELETE, - MHD_HTTP_METHOD_OPTIONS); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _("Identity Provider REST API initialized\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ -void * -libgnunet_plugin_rest_reclaim_done (void *cls) -{ - struct GNUNET_REST_Plugin *api = cls; - struct Plugin *plugin = api->cls; - plugin->cfg = NULL; - - GNUNET_free_non_null (allow_methods); - GNUNET_free (api); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Identity Provider REST plugin is finished\n"); - return NULL; -} - -/* end of plugin_rest_reclaim.c */ diff --git a/src/rest-plugins/Makefile.am b/src/rest-plugins/Makefile.am new file mode 100644 index 000000000..ae74dc78a --- /dev/null +++ b/src/rest-plugins/Makefile.am @@ -0,0 +1,102 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +plugindir = $(libdir)/gnunet + +pkgcfgdir= $(pkgdatadir)/config.d/ + +libexecdir= $(pkglibdir)/libexec/ + + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIBS = -lgcov +endif + +plugin_LTLIBRARIES = \ + libgnunet_plugin_rest_copying.la \ + libgnunet_plugin_rest_peerinfo.la \ + libgnunet_plugin_rest_identity.la \ + libgnunet_plugin_rest_namestore.la \ + libgnunet_plugin_rest_gns.la \ + libgnunet_plugin_rest_openid_connect.la + + +libgnunet_plugin_rest_copying_la_SOURCES = \ + plugin_rest_copying.c +libgnunet_plugin_rest_copying_la_LIBADD = \ + $(top_builddir)/src/rest/libgnunetrest.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ + $(LTLIBINTL) -lmicrohttpd +libgnunet_plugin_rest_copying_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_rest_peerinfo_la_SOURCES = \ + plugin_rest_peerinfo.c +libgnunet_plugin_rest_peerinfo_la_LIBADD = \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/rest/libgnunetrest.la \ + $(top_builddir)/src/json/libgnunetjson.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ + $(LTLIBINTL) -ljansson -lmicrohttpd +libgnunet_plugin_rest_peerinfo_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_rest_identity_la_SOURCES = \ + plugin_rest_identity.c +libgnunet_plugin_rest_identity_la_LIBADD = \ + $(top_builddir)/src/identity/libgnunetidentity.la \ + $(top_builddir)/src/rest/libgnunetrest.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ + $(LTLIBINTL) -ljansson -lmicrohttpd +libgnunet_plugin_rest_identity_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + + + +libgnunet_plugin_rest_namestore_la_SOURCES = \ + plugin_rest_namestore.c +libgnunet_plugin_rest_namestore_la_LIBADD = \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/rest/libgnunetrest.la \ + $(top_builddir)/src/identity/libgnunetidentity.la \ + $(top_builddir)/src/json/libgnunetjson.la \ + $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ + $(LTLIBINTL) -ljansson -lmicrohttpd +libgnunet_plugin_rest_namestore_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_rest_gns_la_SOURCES = \ + plugin_rest_gns.c +libgnunet_plugin_rest_gns_la_LIBADD = \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/rest/libgnunetrest.la \ + $(top_builddir)/src/identity/libgnunetidentity.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ + $(LTLIBINTL) -ljansson -lmicrohttpd +libgnunet_plugin_rest_gns_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_rest_openid_connect_la_SOURCES = \ + plugin_rest_openid_connect.c \ + oidc_helper.c +libgnunet_plugin_rest_openid_connect_la_LIBADD = \ + $(top_builddir)/src/identity/libgnunetidentity.la \ + $(top_builddir)/src/reclaim/libgnunetreclaim.la \ + $(top_builddir)/src/rest/libgnunetrest.la \ + $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \ + $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ +$(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ + $(LTLIBINTL) -ljansson -lmicrohttpd +libgnunet_plugin_rest_openid_connect_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + diff --git a/src/rest-plugins/oidc_helper.c b/src/rest-plugins/oidc_helper.c new file mode 100644 index 000000000..1e9e64fec --- /dev/null +++ b/src/rest-plugins/oidc_helper.c @@ -0,0 +1,440 @@ +/* + This file is part of GNUnet + Copyright (C) 2010-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +/** + * @file reclaim/oidc_helper.c + * @brief helper library for OIDC related functions + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_signatures.h" +#include "gnunet_reclaim_service.h" +#include "gnunet_reclaim_attribute_lib.h" +#include +#include +#include "oidc_helper.h" + +static char* +create_jwt_header(void) +{ + json_t *root; + char *json_str; + + root = json_object (); + json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE)); + json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE)); + + json_str = json_dumps (root, JSON_INDENT(0) | JSON_COMPACT); + json_decref (root); + return json_str; +} + +static void +replace_char(char* str, char find, char replace){ + char *current_pos = strchr(str,find); + while (current_pos){ + *current_pos = replace; + current_pos = strchr(current_pos,find); + } +} + +//RFC4648 +static void +fix_base64(char* str) { + char *padding; + //First, remove trailing padding '=' + padding = strtok(str, "="); + while (NULL != padding) + padding = strtok(NULL, "="); + + //Replace + with - + replace_char (str, '+', '-'); + + //Replace / with _ + replace_char (str, '/', '_'); + +} + +/** + * Create a JWT from attributes + * + * @param aud_key the public of the audience + * @param sub_key the public key of the subject + * @param attrs the attribute list + * @param expiration_time the validity of the token + * @param secret_key the key used to sign the JWT + * @return a new base64-encoded JWT string. + */ +char* +OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, + const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, + const struct GNUNET_TIME_Relative *expiration_time, + const char *nonce, + const char *secret_key) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + struct GNUNET_HashCode signature; + struct GNUNET_TIME_Absolute exp_time; + struct GNUNET_TIME_Absolute time_now; + char* audience; + char* subject; + char* header; + char* body_str; + char* result; + char* header_base64; + char* body_base64; + char* signature_target; + char* signature_base64; + char* attr_val_str; + json_t* body; + + //iat REQUIRED time now + time_now = GNUNET_TIME_absolute_get(); + //exp REQUIRED time expired from config + exp_time = GNUNET_TIME_absolute_add (time_now, *expiration_time); + //auth_time only if max_age + //nonce only if nonce + // OPTIONAL acr,amr,azp + subject = GNUNET_STRINGS_data_to_string_alloc (sub_key, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + audience = GNUNET_STRINGS_data_to_string_alloc (aud_key, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + header = create_jwt_header (); + body = json_object (); + + //iss REQUIRED case sensitive server uri with https + //The issuer is the local reclaim instance (e.g. https://reclaim.id/api/openid) + json_object_set_new (body, + "iss", json_string (SERVER_ADDRESS)); + //sub REQUIRED public key identity, not exceed 255 ASCII length + json_object_set_new (body, + "sub", json_string (subject)); + //aud REQUIRED public key client_id must be there + json_object_set_new (body, + "aud", json_string (audience)); + //iat + json_object_set_new (body, + "iat", json_integer (time_now.abs_value_us / (1000*1000))); + //exp + json_object_set_new (body, + "exp", json_integer (exp_time.abs_value_us / (1000*1000))); + //nbf + json_object_set_new (body, + "nbf", json_integer (time_now.abs_value_us / (1000*1000))); + //nonce + if (NULL != nonce) + json_object_set_new (body, + "nonce", json_string (nonce)); + + for (le = attrs->list_head; NULL != le; le = le->next) + { + attr_val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (le->claim->type, + le->claim->data, + le->claim->data_size); + json_object_set_new (body, + le->claim->name, + json_string (attr_val_str)); + GNUNET_free (attr_val_str); + } + body_str = json_dumps (body, JSON_INDENT(0) | JSON_COMPACT); + json_decref (body); + + GNUNET_STRINGS_base64_encode (header, + strlen (header), + &header_base64); + fix_base64(header_base64); + + GNUNET_STRINGS_base64_encode (body_str, + strlen (body_str), + &body_base64); + fix_base64(body_base64); + + GNUNET_free (subject); + GNUNET_free (audience); + + /** + * Creating the JWT signature. This might not be + * standards compliant, check. + */ + GNUNET_asprintf (&signature_target, "%s.%s", header_base64, body_base64); + GNUNET_CRYPTO_hmac_raw (secret_key, strlen (secret_key), signature_target, strlen (signature_target), &signature); + GNUNET_STRINGS_base64_encode ((const char*)&signature, + sizeof (struct GNUNET_HashCode), + &signature_base64); + fix_base64(signature_base64); + + GNUNET_asprintf (&result, "%s.%s.%s", + header_base64, body_base64, signature_base64); + + GNUNET_free (signature_target); + GNUNET_free (header); + GNUNET_free (body_str); + GNUNET_free (signature_base64); + GNUNET_free (body_base64); + GNUNET_free (header_base64); + return result; +} +/** + * Builds an OIDC authorization code including + * a reclaim ticket and nonce + * + * @param issuer the issuer of the ticket, used to sign the ticket and nonce + * @param ticket the ticket to include in the code + * @param nonce the nonce to include in the code + * @return a new authorization code (caller must free) + */ +char* +OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, + const struct GNUNET_RECLAIM_Ticket *ticket, + const char* nonce) +{ + char *ticket_str; + json_t *code_json; + char *signature_payload; + char *signature_str; + char *authz_code; + size_t signature_payload_len; + struct GNUNET_CRYPTO_EcdsaSignature signature; + struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; + + signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket); + if (NULL != nonce) + signature_payload_len += strlen (nonce); + + signature_payload = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len); + purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *)signature_payload; + purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len); + purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN); + memcpy (&purpose[1], + ticket, + sizeof (struct GNUNET_RECLAIM_Ticket)); + if (NULL != nonce) + memcpy (((char*)&purpose[1]) + sizeof (struct GNUNET_RECLAIM_Ticket), + nonce, + strlen (nonce)); + if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdsa_sign (issuer, + purpose, + &signature)) + { + GNUNET_free (signature_payload); + return NULL; + } + signature_str = GNUNET_STRINGS_data_to_string_alloc (&signature, + sizeof (signature)); + ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket, + sizeof (struct GNUNET_RECLAIM_Ticket)); + + code_json = json_object (); + json_object_set_new (code_json, + "ticket", + json_string (ticket_str)); + if (NULL != nonce) + json_object_set_new (code_json, + "nonce", + json_string (nonce)); + json_object_set_new (code_json, + "signature", + json_string (signature_str)); + authz_code = json_dumps (code_json, + JSON_INDENT(0) | JSON_COMPACT); + GNUNET_free (signature_payload); + GNUNET_free (signature_str); + GNUNET_free (ticket_str); + json_decref (code_json); + return authz_code; +} + + + + +/** + * Parse reclaim ticket and nonce from + * authorization code. + * This also verifies the signature in the code. + * + * @param audience the expected audience of the code + * @param code the string representation of the code + * @param ticket where to store the ticket + * @param nonce where to store the nonce + * @return GNUNET_OK if successful, else GNUNET_SYSERR + */ +int +OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience, + const char* code, + struct GNUNET_RECLAIM_Ticket **ticket, + char **nonce) +{ + json_error_t error; + json_t *code_json; + json_t *ticket_json; + json_t *nonce_json; + json_t *signature_json; + const char *ticket_str; + const char *signature_str; + const char *nonce_str; + char *code_output; + struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; + struct GNUNET_CRYPTO_EcdsaSignature signature; + size_t signature_payload_len; + + code_output = NULL; + GNUNET_STRINGS_base64_decode (code, + strlen(code), + (void**)&code_output); + code_json = json_loads (code_output, 0 , &error); + GNUNET_free (code_output); + ticket_json = json_object_get (code_json, "ticket"); + nonce_json = json_object_get (code_json, "nonce"); + signature_json = json_object_get (code_json, "signature"); + *ticket = NULL; + *nonce = NULL; + + if ((NULL == ticket_json || !json_is_string (ticket_json)) || + (NULL == signature_json || !json_is_string (signature_json))) + { + json_decref (code_json); + return GNUNET_SYSERR; + } + ticket_str = json_string_value (ticket_json); + signature_str = json_string_value (signature_json); + nonce_str = NULL; + if (NULL != nonce_json) + nonce_str = json_string_value (nonce_json); + signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket); + if (NULL != nonce_str) + signature_payload_len += strlen (nonce_str); + purpose = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + + signature_payload_len); + purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len); + purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN); + if (GNUNET_OK != GNUNET_STRINGS_string_to_data (ticket_str, + strlen (ticket_str), + &purpose[1], + sizeof (struct GNUNET_RECLAIM_Ticket))) + { + GNUNET_free (purpose); + json_decref (code_json); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Cannot parse ticket!\n"); + return GNUNET_SYSERR; + } + if (GNUNET_OK != GNUNET_STRINGS_string_to_data (signature_str, + strlen (signature_str), + &signature, + sizeof (struct GNUNET_CRYPTO_EcdsaSignature))) + { + GNUNET_free (purpose); + json_decref (code_json); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Cannot parse signature!\n"); + return GNUNET_SYSERR; + } + *ticket = GNUNET_new (struct GNUNET_RECLAIM_Ticket); + memcpy (*ticket, + &purpose[1], + sizeof (struct GNUNET_RECLAIM_Ticket)); + if (0 != memcmp (audience, + &(*ticket)->audience, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) + { + GNUNET_free (purpose); + GNUNET_free (*ticket); + json_decref (code_json); + *ticket = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Audience in ticket does not match client!\n"); + return GNUNET_SYSERR; + + } + if (NULL != nonce_str) + memcpy (((char*)&purpose[1]) + sizeof (struct GNUNET_RECLAIM_Ticket), + nonce_str, + strlen (nonce_str)); + if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN, + purpose, + &signature, + &(*ticket)->identity)) + { + GNUNET_free (purpose); + GNUNET_free (*ticket); + json_decref (code_json); + *ticket = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Signature of authZ code invalid!\n"); + return GNUNET_SYSERR; + } + *nonce = GNUNET_strdup (nonce_str); + return GNUNET_OK; +} + +/** + * Build a token response for a token request + * TODO: Maybe we should add the scope here? + * + * @param access_token the access token to include + * @param id_token the id_token to include + * @param expiration_time the expiration time of the token(s) + * @param token_response where to store the response + */ +void +OIDC_build_token_response (const char *access_token, + const char *id_token, + const struct GNUNET_TIME_Relative *expiration_time, + char **token_response) +{ + json_t *root_json; + + root_json = json_object (); + + GNUNET_assert (NULL != access_token); + GNUNET_assert (NULL != id_token); + GNUNET_assert (NULL != expiration_time); + json_object_set_new (root_json, + "access_token", + json_string (access_token)); + json_object_set_new (root_json, + "token_type", + json_string ("Bearer")); + json_object_set_new (root_json, + "expires_in", + json_integer (expiration_time->rel_value_us / (1000 * 1000))); + json_object_set_new (root_json, + "id_token", + json_string (id_token)); + *token_response = json_dumps (root_json, + JSON_INDENT(0) | JSON_COMPACT); + json_decref (root_json); +} + +/** + * Generate a new access token + */ +char* +OIDC_access_token_new () +{ + char* access_token_number; + char* access_token; + uint64_t random_number; + + random_number = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); + GNUNET_asprintf (&access_token_number, "%" PRIu64, random_number); + GNUNET_STRINGS_base64_encode(access_token_number,strlen(access_token_number),&access_token); + return access_token; +} diff --git a/src/rest-plugins/oidc_helper.h b/src/rest-plugins/oidc_helper.h new file mode 100644 index 000000000..7a0f45bf9 --- /dev/null +++ b/src/rest-plugins/oidc_helper.h @@ -0,0 +1,109 @@ +/* + This file is part of GNUnet + Copyright (C) 2010-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +/** + * @file reclaim/oidc_helper.h + * @brief helper library for OIDC related functions + * @author Martin Schanzenbach + */ + +#ifndef JWT_H +#define JWT_H + +#define JWT_ALG "alg" + +/* Use 512bit HMAC */ +#define JWT_ALG_VALUE "HS512" + +#define JWT_TYP "typ" + +#define JWT_TYP_VALUE "jwt" + +#define SERVER_ADDRESS "https://reclaim.id" + +/** + * Create a JWT from attributes + * + * @param aud_key the public of the audience + * @param sub_key the public key of the subject + * @param attrs the attribute list + * @param expiration_time the validity of the token + * @param secret_key the key used to sign the JWT + * @return a new base64-encoded JWT string. + */ +char* +OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, + const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, + const struct GNUNET_TIME_Relative *expiration_time, + const char *nonce, + const char *secret_key); + +/** + * Builds an OIDC authorization code including + * a reclaim ticket and nonce + * + * @param issuer the issuer of the ticket, used to sign the ticket and nonce + * @param ticket the ticket to include in the code + * @param nonce the nonce to include in the code + * @return a new authorization code (caller must free) + */ +char* +OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, + const struct GNUNET_RECLAIM_Ticket *ticket, + const char* nonce); + +/** + * Parse reclaim ticket and nonce from + * authorization code. + * This also verifies the signature in the code. + * + * @param audience the expected audience of the code + * @param code the string representation of the code + * @param ticket where to store the ticket + * @param nonce where to store the nonce + * @return GNUNET_OK if successful, else GNUNET_SYSERR + */ +int +OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience, + const char* code, + struct GNUNET_RECLAIM_Ticket **ticket, + char **nonce); + +/** + * Build a token response for a token request + * TODO: Maybe we should add the scope here? + * + * @param access_token the access token to include + * @param id_token the id_token to include + * @param expiration_time the expiration time of the token(s) + * @param token_response where to store the response + */ +void +OIDC_build_token_response (const char *access_token, + const char *id_token, + const struct GNUNET_TIME_Relative *expiration_time, + char **token_response); +/** + * Generate a new access token + */ +char* +OIDC_access_token_new (); + + +#endif diff --git a/src/rest-plugins/plugin_rest_copying.c b/src/rest-plugins/plugin_rest_copying.c new file mode 100644 index 000000000..668dc5d38 --- /dev/null +++ b/src/rest-plugins/plugin_rest_copying.c @@ -0,0 +1,231 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2018 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +/** + * @author Martin Schanzenbach + * @file gns/plugin_rest_copying.c + * @brief REST plugin that serves licensing information. + * + */ + +#include "platform.h" +#include "gnunet_rest_plugin.h" +#include + +#define GNUNET_REST_API_NS_COPYING "/copying" + +#define GNUNET_REST_COPYING_TEXT "GNU Affero General Public License version 3 or later. See also: " + +/** + * @brief struct returned by the initialization function of the plugin + */ +struct Plugin +{ + const struct GNUNET_CONFIGURATION_Handle *cfg; +}; + +const struct GNUNET_CONFIGURATION_Handle *cfg; + +struct RequestHandle +{ + /** + * Handle to rest request + */ + struct GNUNET_REST_RequestHandle *rest_handle; + + /** + * The plugin result processor + */ + GNUNET_REST_ResultProcessor proc; + + /** + * The closure of the result processor + */ + void *proc_cls; + + /** + * HTTP response code + */ + int response_code; + +}; + + +/** + * Cleanup request handle. + * + * @param handle Handle to clean up + */ +static void +cleanup_handle (struct RequestHandle *handle) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up\n"); + GNUNET_free (handle); +} + + +/** + * Task run on shutdown. Cleans up everything. + * + * @param cls unused + * @param tc scheduler context + */ +static void +do_error (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, handle->response_code); + cleanup_handle (handle); +} + + +/** + * Handle rest request + * + * @param handle the lookup handle + */ +static void +get_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct MHD_Response *resp; + struct RequestHandle *handle = cls; + + resp = GNUNET_REST_create_response (GNUNET_REST_COPYING_TEXT); + handle->proc (handle->proc_cls, + resp, + MHD_HTTP_OK); + cleanup_handle (handle); +} + + + +/** + * Handle rest request + * + * @param handle the lookup handle + */ +static void +options_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct MHD_Response *resp; + struct RequestHandle *handle = cls; + + resp = GNUNET_REST_create_response (NULL); + MHD_add_response_header (resp, + "Access-Control-Allow-Methods", + MHD_HTTP_METHOD_GET); + handle->proc (handle->proc_cls, + resp, + MHD_HTTP_OK); + cleanup_handle (handle); +} + + +/** + * Function processing the REST call + * + * @param method HTTP method + * @param url URL of the HTTP request + * @param data body of the HTTP request (optional) + * @param data_size length of the body + * @param proc callback function for the result + * @param proc_cls closure for @a proc + * @return #GNUNET_OK if request accepted + */ +static void +rest_copying_process_request (struct GNUNET_REST_RequestHandle *conndata_handle, + GNUNET_REST_ResultProcessor proc, + void *proc_cls) +{ + static const struct GNUNET_REST_RequestHandler handlers[] = { + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_COPYING, &get_cont}, + {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_COPYING, &options_cont}, + GNUNET_REST_HANDLER_END + }; + struct RequestHandle *handle = GNUNET_new (struct RequestHandle); + struct GNUNET_REST_RequestHandlerError err; + + handle->proc_cls = proc_cls; + handle->proc = proc; + handle->rest_handle = conndata_handle; + + if (GNUNET_NO == GNUNET_REST_handle_request (conndata_handle, + handlers, + &err, + handle)) + { + handle->response_code = err.error_code; + GNUNET_SCHEDULER_add_now (&do_error, handle); + } +} + + +/** + * Entry point for the plugin. + * + * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*" + * @return NULL on error, otherwise the plugin context + */ +void * +libgnunet_plugin_rest_copying_init (void *cls) +{ + static struct Plugin plugin; + cfg = cls; + struct GNUNET_REST_Plugin *api; + + if (NULL != plugin.cfg) + return NULL; /* can only initialize once! */ + memset (&plugin, 0, sizeof (struct Plugin)); + plugin.cfg = cfg; + api = GNUNET_new (struct GNUNET_REST_Plugin); + api->cls = &plugin; + api->name = GNUNET_REST_API_NS_COPYING; + api->process_request = &rest_copying_process_request; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("COPYING REST API initialized\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the plugin context (as returned by "init") + * @return always NULL + */ +void * +libgnunet_plugin_rest_copying_done (void *cls) +{ + struct GNUNET_REST_Plugin *api = cls; + struct Plugin *plugin = api->cls; + + plugin->cfg = NULL; + GNUNET_free (api); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "COPYING REST plugin is finished\n"); + return NULL; +} + +/* end of plugin_rest_copying.c */ diff --git a/src/rest-plugins/plugin_rest_gns.c b/src/rest-plugins/plugin_rest_gns.c new file mode 100644 index 000000000..0bf4198fc --- /dev/null +++ b/src/rest-plugins/plugin_rest_gns.c @@ -0,0 +1,476 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +/** + * @author Philippe Buschmann + * @file gns/plugin_rest_gns.c + * @brief GNUnet Gns REST plugin + */ + +#include "platform.h" +#include "gnunet_rest_plugin.h" +#include "gnunet_rest_lib.h" +#include "gnunet_json_lib.h" +#include "gnunet_gnsrecord_lib.h" +#include "gnunet_gns_service.h" +#include "microhttpd.h" +#include + +/** + * Rest API GNS Namespace + */ +#define GNUNET_REST_API_NS_GNS "/gns" + +/** + * Rest API GNS Parameter record_type + */ +#define GNUNET_REST_GNS_PARAM_RECORD_TYPE "record_type" + +/** + * Rest API GNS ERROR Unknown Error + */ +#define GNUNET_REST_GNS_ERROR_UNKNOWN "Unknown Error" + +/** + * Rest API GNS ERROR Record not found + */ +#define GNUNET_REST_GNS_NOT_FOUND "Record not found" + +/** + * The configuration handle + */ +const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * HTTP methods allows for this plugin + */ +static char* allow_methods; + +/** + * @brief struct returned by the initialization function of the plugin + */ +struct Plugin +{ + const struct GNUNET_CONFIGURATION_Handle *cfg; +}; + +/** + * The request handle + */ +struct RequestHandle +{ + + /** + * Connection to GNS + */ + struct GNUNET_GNS_Handle *gns; + + /** + * Active GNS lookup + */ + struct GNUNET_GNS_LookupWithTldRequest *gns_lookup; + + /** + * Name to look up + */ + char *name; + + /** + * Record type to look up + */ + int record_type; + + /** + * Rest connection + */ + struct GNUNET_REST_RequestHandle *rest_handle; + + /** + * Desired timeout for the lookup (default is no timeout). + */ + struct GNUNET_TIME_Relative timeout; + + /** + * ID of a task associated with the resolution process. + */ + struct GNUNET_SCHEDULER_Task *timeout_task; + + /** + * The plugin result processor + */ + GNUNET_REST_ResultProcessor proc; + + /** + * The closure of the result processor + */ + void *proc_cls; + + /** + * The url + */ + char *url; + + /** + * Error response message + */ + char *emsg; + + /** + * Response code + */ + int response_code; + +}; + + +/** + * Cleanup lookup handle + * @param handle Handle to clean up + */ +static void +cleanup_handle (void *cls) +{ + struct RequestHandle *handle = cls; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up\n"); + + if (NULL != handle->gns_lookup) + { + GNUNET_GNS_lookup_with_tld_cancel (handle->gns_lookup); + handle->gns_lookup = NULL; + } + if (NULL != handle->gns) + { + GNUNET_GNS_disconnect (handle->gns); + handle->gns = NULL; + } + + if (NULL != handle->timeout_task) + { + GNUNET_SCHEDULER_cancel (handle->timeout_task); + handle->timeout_task = NULL; + } + if (NULL != handle->url) + GNUNET_free (handle->url); + if (NULL != handle->name) + GNUNET_free (handle->name); + if (NULL != handle->emsg) + GNUNET_free (handle->emsg); + + GNUNET_free (handle); +} + + +/** + * Task run on errors. Reports an error and cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_error (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + json_t *json_error = json_object(); + char *response; + + if (NULL == handle->emsg) + handle->emsg = GNUNET_strdup(GNUNET_REST_GNS_ERROR_UNKNOWN); + + json_object_set_new(json_error,"error", json_string(handle->emsg)); + + if (0 == handle->response_code) + handle->response_code = MHD_HTTP_OK; + response = json_dumps (json_error, 0); + resp = GNUNET_REST_create_response (response); + handle->proc (handle->proc_cls, resp, handle->response_code); + json_decref(json_error); + GNUNET_free(response); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + +/** + * Iterator called on obtained result for a GNS lookup. + * + * @param cls closure with the object + * @param was_gns #GNUNET_NO if name was not a GNS name + * @param rd_count number of records in @a rd + * @param rd the records in reply + */ +static void +handle_gns_response (void *cls, + int was_gns, + uint32_t rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + json_t *result_array; + json_t *record_obj; + char *result; + + handle->gns_lookup = NULL; + + if (GNUNET_NO == was_gns) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_GNS_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + result_array = json_array(); + for (uint32_t i=0;irecord_type) && + (GNUNET_GNSRECORD_TYPE_ANY != handle->record_type) ) + { + continue; + } + + record_obj = GNUNET_JSON_from_gns_record(NULL,&rd[i]); + json_array_append (result_array, record_obj); + json_decref (record_obj); + } + + result = json_dumps(result_array, 0); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result); + resp = GNUNET_REST_create_response (result); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free (result); + json_decref (result_array); + GNUNET_SCHEDULER_add_now(&cleanup_handle, handle); +} + + +/** + * Handle gns GET request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +get_gns_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct GNUNET_HashCode key; + char *record_type; + char *name; + + name = NULL; + handle->name = NULL; + if (strlen (GNUNET_REST_API_NS_GNS) < strlen (handle->url)) + { + name = &handle->url[strlen (GNUNET_REST_API_NS_GNS) + 1]; + } + + if (NULL == name) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_GNS_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (0 >= strlen (name)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_GNS_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->name = GNUNET_strdup(name); + + handle->record_type = UINT32_MAX; + GNUNET_CRYPTO_hash (GNUNET_REST_GNS_PARAM_RECORD_TYPE, + strlen (GNUNET_REST_GNS_PARAM_RECORD_TYPE), + &key); + if ( GNUNET_YES + == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, + &key)) + { + record_type = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key); + handle->record_type = GNUNET_GNSRECORD_typename_to_number(record_type); + } + + if(UINT32_MAX == handle->record_type) + { + handle->record_type = GNUNET_GNSRECORD_TYPE_ANY; + } + + handle->gns_lookup = GNUNET_GNS_lookup_with_tld (handle->gns, + handle->name, + handle->record_type, + GNUNET_NO, + &handle_gns_response, + handle); +} + + + +/** + * Respond to OPTIONS request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +options_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct MHD_Response *resp; + struct RequestHandle *handle = cls; + + //independent of path return all options + resp = GNUNET_REST_create_response (NULL); + MHD_add_response_header (resp, + "Access-Control-Allow-Methods", + allow_methods); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_SCHEDULER_add_now(&cleanup_handle, handle); + return; +} + + +/** + * Handle rest request + * + * @param handle the request handle + */ +static void +init_cont (struct RequestHandle *handle) +{ + struct GNUNET_REST_RequestHandlerError err; + static const struct GNUNET_REST_RequestHandler handlers[] = { + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_GNS, &get_gns_cont}, + {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_GNS, &options_cont}, + GNUNET_REST_HANDLER_END + }; + + if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, + handlers, + &err, + handle)) + { + handle->response_code = err.error_code; + GNUNET_SCHEDULER_add_now (&do_error, handle); + } +} + + +/** + * Function processing the REST call + * + * @param method HTTP method + * @param url URL of the HTTP request + * @param data body of the HTTP request (optional) + * @param data_size length of the body + * @param proc callback function for the result + * @param proc_cls closure for callback function + * @return GNUNET_OK if request accepted + */ +static void +rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle, + GNUNET_REST_ResultProcessor proc, + void *proc_cls) +{ + struct RequestHandle *handle = GNUNET_new (struct RequestHandle); + + handle->response_code = 0; + handle->timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60); + handle->proc_cls = proc_cls; + handle->proc = proc; + handle->rest_handle = rest_handle; + + handle->url = GNUNET_strdup (rest_handle->url); + if (handle->url[strlen (handle->url)-1] == '/') + handle->url[strlen (handle->url)-1] = '\0'; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); + handle->gns = GNUNET_GNS_connect (cfg); + init_cont(handle); + + handle->timeout_task = + GNUNET_SCHEDULER_add_delayed (handle->timeout, + &do_error, + handle); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); +} + + +/** + * Entry point for the plugin. + * + * @param cls Config info + * @return NULL on error, otherwise the plugin context + */ +void * +libgnunet_plugin_rest_gns_init (void *cls) +{ + static struct Plugin plugin; + struct GNUNET_REST_Plugin *api; + + cfg = cls; + if (NULL != plugin.cfg) + return NULL; /* can only initialize once! */ + memset (&plugin, 0, sizeof (struct Plugin)); + plugin.cfg = cfg; + api = GNUNET_new (struct GNUNET_REST_Plugin); + api->cls = &plugin; + api->name = GNUNET_REST_API_NS_GNS; + api->process_request = &rest_process_request; + GNUNET_asprintf (&allow_methods, + "%s, %s, %s, %s, %s", + MHD_HTTP_METHOD_GET, + MHD_HTTP_METHOD_POST, + MHD_HTTP_METHOD_PUT, + MHD_HTTP_METHOD_DELETE, + MHD_HTTP_METHOD_OPTIONS); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Gns REST API initialized\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the plugin context (as returned by "init") + * @return always NULL + */ +void * +libgnunet_plugin_rest_gns_done (void *cls) +{ + struct GNUNET_REST_Plugin *api = cls; + struct Plugin *plugin = api->cls; + plugin->cfg = NULL; + + GNUNET_free_non_null (allow_methods); + GNUNET_free (api); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Gns REST plugin is finished\n"); + return NULL; +} + +/* end of plugin_rest_gns.c */ + diff --git a/src/rest-plugins/plugin_rest_identity.c b/src/rest-plugins/plugin_rest_identity.c new file mode 100644 index 000000000..9f1765a63 --- /dev/null +++ b/src/rest-plugins/plugin_rest_identity.c @@ -0,0 +1,1319 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +/** + * @author Martin Schanzenbach + * @author Philippe Buschmann + * @file identity/plugin_rest_identity.c + * @brief GNUnet Identity REST plugin + */ + +#include "platform.h" +#include "gnunet_rest_plugin.h" +#include "gnunet_identity_service.h" +#include "gnunet_rest_lib.h" +#include "microhttpd.h" +#include + +/** + * Identity Namespace + */ +#define GNUNET_REST_API_NS_IDENTITY "/identity" + +/** + * Identity Namespace with public key specifier + */ +#define GNUNET_REST_API_NS_IDENTITY_ALL "/identity/all" + +/** + * Identity Namespace with public key specifier + */ +#define GNUNET_REST_API_NS_IDENTITY_PUBKEY "/identity/pubkey" + +/** + * Identity Namespace with public key specifier + */ +#define GNUNET_REST_API_NS_IDENTITY_NAME "/identity/name" + +/** + * Identity Subsystem Namespace + */ +#define GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM "/identity/subsystem" + +/** + * Parameter public key + */ +#define GNUNET_REST_IDENTITY_PARAM_PUBKEY "pubkey" + +/** + * Parameter subsystem + */ +#define GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM "subsystem" + +/** + * Parameter name + */ +#define GNUNET_REST_IDENTITY_PARAM_NAME "name" + +/** + * Parameter new name + */ +#define GNUNET_REST_IDENTITY_PARAM_NEWNAME "newname" + +/** + * Error message Unknown Error + */ +#define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error" + +/** + * Error message No identity found + */ +#define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found" + +/** + * Error message Missing identity name + */ +#define GNUNET_REST_IDENTITY_MISSING_NAME "Missing identity name" + +/** + * Error message Missing identity name + */ +#define GNUNET_REST_IDENTITY_MISSING_PUBKEY "Missing identity public key" + +/** + * Error message No data + */ +#define GNUNET_REST_ERROR_NO_DATA "No data" + +/** + * Error message Data invalid + */ +#define GNUNET_REST_ERROR_DATA_INVALID "Data invalid" + +/** + * State while collecting all egos + */ +#define ID_REST_STATE_INIT 0 + +/** + * Done collecting egos + */ +#define ID_REST_STATE_POST_INIT 1 + +/** + * The configuration handle + */ +const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * HTTP methods allows for this plugin + */ +static char* allow_methods; + +/** + * @brief struct returned by the initialization function of the plugin + */ +struct Plugin +{ + const struct GNUNET_CONFIGURATION_Handle *cfg; +}; + +/** + * The ego list + */ +struct EgoEntry +{ + /** + * DLL + */ + struct EgoEntry *next; + + /** + * DLL + */ + struct EgoEntry *prev; + + /** + * Ego Identifier + */ + char *identifier; + + /** + * Public key string + */ + char *keystring; + + /** + * The Ego + */ + struct GNUNET_IDENTITY_Ego *ego; +}; + +/** + * The request handle + */ +struct RequestHandle +{ + /** + * The data from the REST request + */ + const char* data; + + /** + * The name to look up + */ + char *name; + + /** + * the length of the REST data + */ + size_t data_size; + + + /** + * Ego list + */ + struct EgoEntry *ego_head; + + /** + * Ego list + */ + struct EgoEntry *ego_tail; + + /** + * The processing state + */ + int state; + + /** + * Handle to Identity service. + */ + struct GNUNET_IDENTITY_Handle *identity_handle; + + /** + * IDENTITY Operation + */ + struct GNUNET_IDENTITY_Operation *op; + + /** + * Rest connection + */ + struct GNUNET_REST_RequestHandle *rest_handle; + + /** + * Desired timeout for the lookup (default is no timeout). + */ + struct GNUNET_TIME_Relative timeout; + + /** + * ID of a task associated with the resolution process. + */ + struct GNUNET_SCHEDULER_Task *timeout_task; + + /** + * The plugin result processor + */ + GNUNET_REST_ResultProcessor proc; + + /** + * The closure of the result processor + */ + void *proc_cls; + + /** + * The url + */ + char *url; + + /** + * Error response message + */ + char *emsg; + + /** + * Response code + */ + int response_code; + +}; + +/** + * Cleanup lookup handle + * @param handle Handle to clean up + */ +static void +cleanup_handle (void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct EgoEntry *ego_tmp; + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); + if (NULL != handle->timeout_task) + { + GNUNET_SCHEDULER_cancel (handle->timeout_task); + handle->timeout_task = NULL; + } + + if (NULL != handle->url) + GNUNET_free(handle->url); + if (NULL != handle->emsg) + GNUNET_free(handle->emsg); + if (NULL != handle->name) + GNUNET_free (handle->name); + if (NULL != handle->identity_handle) + GNUNET_IDENTITY_disconnect (handle->identity_handle); + + for (ego_entry = handle->ego_head; + NULL != ego_entry;) + { + ego_tmp = ego_entry; + ego_entry = ego_entry->next; + GNUNET_free(ego_tmp->identifier); + GNUNET_free(ego_tmp->keystring); + GNUNET_free(ego_tmp); + } + + GNUNET_free(handle); +} + +/** + * Task run on errors. Reports an error and cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_error (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + json_t *json_error = json_object(); + char *response; + + if (NULL == handle->emsg) + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_ERROR_UNKNOWN); + + json_object_set_new(json_error,"error", json_string(handle->emsg)); + + if (0 == handle->response_code) + handle->response_code = MHD_HTTP_OK; + response = json_dumps (json_error, 0); + resp = GNUNET_REST_create_response (response); + handle->proc (handle->proc_cls, resp, handle->response_code); + json_decref(json_error); + GNUNET_free(response); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + + +/** + * Get EgoEntry from list with either a public key or a name + * If public key and name are not NULL, it returns the public key result first + * + * @param handle the RequestHandle + * @param pubkey the public key of an identity (only one can be NULL) + * @param name the name of an identity (only one can be NULL) + * @return EgoEntry or NULL if not found + */ +struct EgoEntry* +get_egoentry(struct RequestHandle *handle, char* pubkey, char *name) +{ + struct EgoEntry *ego_entry; + if (NULL != pubkey) + { + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + { + if (0 != strcasecmp (pubkey, ego_entry->keystring)) + continue; + return ego_entry; + } + } + if (NULL != name) + { + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + { + if (0 != strcasecmp (name, ego_entry->identifier)) + continue; + return ego_entry; + } + } + return NULL; +} + + +/** + * Callback for GET Request with subsystem + * + * @param cls the RequestHandle + * @param ego the Ego found + * @param ctx the context + * @param name the id of the ego + */ +static void +ego_get_for_subsystem (void *cls, + struct GNUNET_IDENTITY_Ego *ego, + void **ctx, + const char *name) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + struct GNUNET_CRYPTO_EcdsaPublicKey public_key; + json_t *json_root; + char *result_str; + char *public_key_string; + + if(NULL == ego) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + GNUNET_IDENTITY_ego_get_public_key(ego,&public_key); + public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string(&public_key); + + // create json with subsystem identity + json_root = json_object (); + json_object_set_new (json_root, + GNUNET_REST_IDENTITY_PARAM_PUBKEY, + json_string(public_key_string)); + json_object_set_new (json_root, + GNUNET_REST_IDENTITY_PARAM_NAME, + json_string(name)); + + result_str = json_dumps (json_root, 0); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); + resp = GNUNET_REST_create_response (result_str); + + json_decref (json_root); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free(result_str); + GNUNET_free(public_key_string); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + +/** + * Handle identity GET request for subsystem + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_get_subsystem (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + char *subsystem; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url)) + { + handle->emsg = GNUNET_strdup("Missing subsystem name"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + subsystem = &handle->url[strlen ( + GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) + 1]; + //requested default identity of subsystem + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsystem); + + handle->op = GNUNET_IDENTITY_get (handle->identity_handle, + subsystem, + &ego_get_for_subsystem, + handle); + + if (NULL == handle->op) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } +} + + +/** + * Handle identity GET request - responds with all identities + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_get_all (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct MHD_Response *resp; + json_t *json_root; + json_t *json_ego; + char *result_str; + + json_root = json_array (); + //Return ego/egos + for (ego_entry = handle->ego_head; + NULL != ego_entry; ego_entry = ego_entry->next) + { + json_ego = json_object (); + json_object_set_new (json_ego, + GNUNET_REST_IDENTITY_PARAM_PUBKEY, + json_string (ego_entry->keystring)); + json_object_set_new (json_ego, + GNUNET_REST_IDENTITY_PARAM_NAME, + json_string (ego_entry->identifier)); + json_array_append (json_root, json_ego); + json_decref (json_ego); + } + + if ((size_t) 0 == json_array_size (json_root)) + { + json_decref (json_root); + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + result_str = json_dumps (json_root, 0); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); + resp = GNUNET_REST_create_response (result_str); + + json_decref (json_root); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free(result_str); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + +/** + * Responds with the ego_entry identity + * + * @param handle the struct RequestHandle + * @param ego_entry the struct EgoEntry for the response + */ +void +ego_get_response (struct RequestHandle *handle, struct EgoEntry *ego_entry) +{ + struct MHD_Response *resp; + json_t *json_ego; + char *result_str; + + json_ego = json_object (); + json_object_set_new (json_ego, + GNUNET_REST_IDENTITY_PARAM_PUBKEY, + json_string (ego_entry->keystring)); + json_object_set_new (json_ego, + GNUNET_REST_IDENTITY_PARAM_NAME, + json_string (ego_entry->identifier)); + + result_str = json_dumps (json_ego, 0); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); + resp = GNUNET_REST_create_response (result_str); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + + json_decref (json_ego); + GNUNET_free(result_str); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + +/** + * Handle identity GET request with a public key + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *keystring; + + keystring = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1]; + ego_entry = get_egoentry(handle, keystring, NULL); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + ego_get_response(handle, ego_entry); +} + +/** + * Handle identity GET request with a name + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_get_name (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *egoname; + + egoname = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + egoname = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1]; + ego_entry = get_egoentry(handle, NULL, egoname); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + ego_get_response(handle, ego_entry); +} + + +/** + * Processing finished + * + * @param cls request handle + * @param emsg error message + */ +static void +do_finished (void *cls, const char *emsg) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + + handle->op = NULL; + if (NULL != emsg) + { + handle->emsg = GNUNET_strdup(emsg); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (0 == handle->response_code) + { + handle->response_code = MHD_HTTP_NO_CONTENT; + } + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, handle->response_code); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + +/** + * Processing edit ego with EgoEntry ego_entry + * + * @param handle the struct RequestHandle + * @param ego_entry the struct EgoEntry we want to edit + */ +void +ego_edit (struct RequestHandle *handle, struct EgoEntry *ego_entry) +{ + struct EgoEntry *ego_entry_tmp; + struct MHD_Response *resp; + json_t *data_js; + json_error_t err; + char *newname; + char term_data[handle->data_size + 1]; + int json_state; + + //if no data + if (0 >= handle->data_size) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + //if not json + term_data[handle->data_size] = '\0'; + GNUNET_memcpy(term_data, handle->data, handle->data_size); + data_js = json_loads (term_data,JSON_DECODE_ANY,&err); + + if (NULL == data_js) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + newname = NULL; + //NEW NAME + json_state = 0; + json_state = json_unpack(data_js, + "{s:s!}", + GNUNET_REST_IDENTITY_PARAM_NEWNAME, + &newname); + //Change name with pubkey or name identifier + if (0 != json_state) + { + + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + if (NULL == newname) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + if (0 >= strlen (newname)) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + ego_entry_tmp = get_egoentry (handle, NULL, newname); + if (NULL != ego_entry_tmp) + { + //Ego with same name not allowed (even if its the ego we change) + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); + json_decref (data_js); + return; + } + handle->op = GNUNET_IDENTITY_rename (handle->identity_handle, + ego_entry->identifier, + newname, + &do_finished, + handle); + if (NULL == handle->op) + { + handle->emsg = GNUNET_strdup("Rename failed"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + json_decref (data_js); + return; + +} + + +/** + * Handle identity PUT request with public key + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_edit_pubkey (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *keystring; + + keystring = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1]; + ego_entry = get_egoentry(handle, keystring, NULL); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + ego_edit(handle,ego_entry); +} + +/** + * Handle identity PUT request with name + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *name; + + name = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1]; + ego_entry = get_egoentry(handle, NULL, name); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + ego_edit(handle,ego_entry); +} + +/** + * Handle identity subsystem PUT request with name + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_edit_subsystem (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + json_t *data_js; + json_error_t err; + char *newsubsys; + char *name; + char term_data[handle->data_size + 1]; + int json_state; + + name = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM)+1]; + ego_entry = get_egoentry(handle, NULL, name); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + //if no data + if (0 >= handle->data_size) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + //if not json + term_data[handle->data_size] = '\0'; + GNUNET_memcpy(term_data, handle->data, handle->data_size); + data_js = json_loads (term_data,JSON_DECODE_ANY,&err); + + if (NULL == data_js) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + newsubsys = NULL; + //SUBSYSTEM + json_state = 0; + json_state = json_unpack(data_js, + "{s:s!}", + GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM, + &newsubsys); + //Change subsystem with pubkey or name identifier + if (0 != json_state) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + if (NULL == newsubsys) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + if (0 >= strlen (newsubsys)) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + handle->response_code = MHD_HTTP_NO_CONTENT; + handle->op = GNUNET_IDENTITY_set (handle->identity_handle, + newsubsys, + ego_entry->ego, + &do_finished, + handle); + if (NULL == handle->op) + { + handle->emsg = GNUNET_strdup("Setting subsystem failed"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + json_decref (data_js); + return; + +} + +/** + * Handle identity POST request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_create (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct MHD_Response *resp; + json_t *data_js; + json_error_t err; + char* egoname; + int json_unpack_state; + char term_data[handle->data_size + 1]; + + if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url)) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + if (0 >= handle->data_size) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + term_data[handle->data_size] = '\0'; + GNUNET_memcpy(term_data, handle->data, handle->data_size); + data_js = json_loads (term_data, + JSON_DECODE_ANY, + &err); + if (NULL == data_js) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + json_unpack_state = 0; + json_unpack_state = json_unpack(data_js, + "{s:s!}", + GNUNET_REST_IDENTITY_PARAM_NAME, + &egoname); + if (0 != json_unpack_state) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + + if (NULL == egoname) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + if (0 >= strlen (egoname)) + { + json_decref (data_js); + handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + GNUNET_STRINGS_utf8_tolower(egoname, egoname); + for (ego_entry = handle->ego_head; + NULL != ego_entry; ego_entry = ego_entry->next) + { + if (0 == strcasecmp (egoname, ego_entry->identifier)) + { + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); + json_decref (data_js); + return; + } + } + handle->name = GNUNET_strdup(egoname); + json_decref (data_js); + handle->response_code = MHD_HTTP_CREATED; + handle->op = GNUNET_IDENTITY_create (handle->identity_handle, handle->name, + &do_finished, handle); +} + +/** + * Handle identity DELETE request with public key + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *keystring; + + keystring = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1]; + ego_entry = get_egoentry(handle, keystring, NULL); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + handle->response_code = MHD_HTTP_NO_CONTENT; + handle->op = GNUNET_IDENTITY_delete (handle->identity_handle, + ego_entry->identifier, + &do_finished, + handle); +} + + +/** + * Handle identity DELETE request with name + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *name; + + name = NULL; + + if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1]; + ego_entry = get_egoentry(handle, NULL, name); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + handle->response_code = MHD_HTTP_NO_CONTENT; + handle->op = GNUNET_IDENTITY_delete (handle->identity_handle, + ego_entry->identifier, + &do_finished, + handle); +} + + +/** + * Respond to OPTIONS request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +options_cont (struct GNUNET_REST_RequestHandle *con_handle, const char* url, + void *cls) +{ + struct MHD_Response *resp; + struct RequestHandle *handle = cls; + + //For now, independent of path return all options + resp = GNUNET_REST_create_response (NULL); + MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); + return; +} + +/** + * Handle rest request + * + * @param handle the request handle + */ +static void +init_cont (struct RequestHandle *handle) +{ + struct GNUNET_REST_RequestHandlerError err; + static const struct GNUNET_REST_RequestHandler handlers[] = { + { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ALL, &ego_get_all }, + { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_get_pubkey }, + { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_get_name }, + { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_get_subsystem }, + { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_edit_pubkey }, + { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_edit_name }, + { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_edit_subsystem }, + { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create }, + { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_delete_pubkey }, + { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_delete_name }, + { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont }, + GNUNET_REST_HANDLER_END + }; + + if (GNUNET_NO + == GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, + handle)) + { + handle->response_code = err.error_code; + GNUNET_SCHEDULER_add_now (&do_error, handle); + } +} + +/** + * If listing is enabled, prints information about the egos. + * + * This function is initially called for all egos and then again + * whenever a ego's identifier changes or if it is deleted. At the + * end of the initial pass over all egos, the function is once called + * with 'NULL' for 'ego'. That does NOT mean that the callback won't + * be invoked in the future or that there was an error. + * + * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', + * this function is only called ONCE, and 'NULL' being passed in + * 'ego' does indicate an error (i.e. name is taken or no default + * value is known). If 'ego' is non-NULL and if '*ctx' + * is set in those callbacks, the value WILL be passed to a subsequent + * call to the identity callback of 'GNUNET_IDENTITY_connect' (if + * that one was not NULL). + * + * When an identity is renamed, this function is called with the + * (known) ego but the NEW identifier. + * + * When an identity is deleted, this function is called with the + * (known) ego and "NULL" for the 'identifier'. In this case, + * the 'ego' is henceforth invalid (and the 'ctx' should also be + * cleaned up). + * + * @param cls closure + * @param ego ego handle + * @param ctx context for application to store data for this ego + * (during the lifetime of this process, initially NULL) + * @param identifier identifier assigned by the user for this ego, + * NULL if the user just deleted the ego and it + * must thus no longer be used + */ +static void +init_egos (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx, + const char *identifier) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct GNUNET_CRYPTO_EcdsaPublicKey pk; + + if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state)) + { + handle->state = ID_REST_STATE_POST_INIT; + init_cont (handle); + return; + } + if (ID_REST_STATE_INIT == handle->state) + { + ego_entry = GNUNET_new(struct EgoEntry); + GNUNET_IDENTITY_ego_get_public_key (ego, &pk); + ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); + ego_entry->ego = ego; + GNUNET_asprintf (&ego_entry->identifier, "%s", identifier); + GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail, + ego_entry); + } +} + +/** + * Function processing the REST call + * + * @param method HTTP method + * @param url URL of the HTTP request + * @param data body of the HTTP request (optional) + * @param data_size length of the body + * @param proc callback function for the result + * @param proc_cls closure for callback function + * @return GNUNET_OK if request accepted + */ +static void +rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle, + GNUNET_REST_ResultProcessor proc, void *proc_cls) +{ + struct RequestHandle *handle = GNUNET_new(struct RequestHandle); + + handle->response_code = 0; + handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; + handle->proc_cls = proc_cls; + handle->proc = proc; + handle->rest_handle = rest_handle; + handle->data = rest_handle->data; + handle->data_size = rest_handle->data_size; + + handle->url = GNUNET_strdup(rest_handle->url); + if (handle->url[strlen (handle->url) - 1] == '/') + handle->url[strlen (handle->url) - 1] = '\0'; + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); + + handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &init_egos, handle); + + handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout, + &do_error, handle); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); +} + +/** + * Entry point for the plugin. + * + * @param cls Config info + * @return NULL on error, otherwise the plugin context + */ +void * +libgnunet_plugin_rest_identity_init (void *cls) +{ + static struct Plugin plugin; + struct GNUNET_REST_Plugin *api; + + cfg = cls; + if (NULL != plugin.cfg) + return NULL; /* can only initialize once! */ + memset (&plugin, 0, sizeof(struct Plugin)); + plugin.cfg = cfg; + api = GNUNET_new(struct GNUNET_REST_Plugin); + api->cls = &plugin; + api->name = GNUNET_REST_API_NS_IDENTITY; + api->process_request = &rest_process_request; + GNUNET_asprintf (&allow_methods, "%s, %s, %s, %s, %s", + MHD_HTTP_METHOD_GET, + MHD_HTTP_METHOD_POST, + MHD_HTTP_METHOD_PUT, + MHD_HTTP_METHOD_DELETE, + MHD_HTTP_METHOD_OPTIONS); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Identity REST API initialized\n")); + return api; +} + +/** + * Exit point from the plugin. + * + * @param cls the plugin context (as returned by "init") + * @return always NULL + */ +void * +libgnunet_plugin_rest_identity_done (void *cls) +{ + struct GNUNET_REST_Plugin *api = cls; + struct Plugin *plugin = api->cls; + plugin->cfg = NULL; + + GNUNET_free_non_null(allow_methods); + GNUNET_free(api); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n"); + return NULL; +} + +/* end of plugin_rest_identity.c */ + diff --git a/src/rest-plugins/plugin_rest_namestore.c b/src/rest-plugins/plugin_rest_namestore.c new file mode 100644 index 000000000..1d72d13ff --- /dev/null +++ b/src/rest-plugins/plugin_rest_namestore.c @@ -0,0 +1,1004 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +/** + * @author Martin Schanzenbach + * @author Philippe Buschmann + * @file namestore/plugin_rest_namestore.c + * @brief GNUnet Namestore REST plugin + */ + +#include "platform.h" +#include "gnunet_rest_plugin.h" +#include "gnunet_gns_service.h" +#include "gnunet_namestore_service.h" +#include "gnunet_identity_service.h" +#include "gnunet_rest_lib.h" +#include "gnunet_json_lib.h" +#include "microhttpd.h" +#include + +/** + * Namestore Namespace + */ +#define GNUNET_REST_API_NS_NAMESTORE "/namestore" + +/** + * Error message Unknown Error + */ +#define GNUNET_REST_NAMESTORE_ERROR_UNKNOWN "Unknown Error" + +/** + * Error message No identity found + */ +#define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found" + +/** + * Error message No default zone specified + */ +#define GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE "No default zone specified" + +/** + * Error message Failed request + */ +#define GNUNET_REST_NAMESTORE_FAILED "Namestore action failed" + +/** + * Error message invalid data + */ +#define GNUNET_REST_NAMESTORE_INVALID_DATA "Data invalid" + +/** + * Error message No data + */ +#define GNUNET_REST_NAMESTORE_NO_DATA "No data" + +/** + * State while collecting all egos + */ +#define ID_REST_STATE_INIT 0 + +/** + * Done collecting egos + */ +#define ID_REST_STATE_POST_INIT 1 +/** + * The configuration handle + */ +const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * HTTP methods allows for this plugin + */ +static char* allow_methods; + +/** + * @brief struct returned by the initialization function of the plugin + */ +struct Plugin +{ + const struct GNUNET_CONFIGURATION_Handle *cfg; +}; + +/** + * The default namestore ego + */ +struct EgoEntry +{ + /** + * DLL + */ + struct EgoEntry *next; + + /** + * DLL + */ + struct EgoEntry *prev; + + /** + * Ego Identifier + */ + char *identifier; + + /** + * Public key string + */ + char *keystring; + + /** + * The Ego + */ + struct GNUNET_IDENTITY_Ego *ego; +}; + +/** + * The request handle + */ +struct RequestHandle +{ + /** + * Records to store + */ + char *record_name; + + /** + * Records to store + */ + struct GNUNET_GNSRECORD_Data *rd; + + /** + * NAMESTORE Operation + */ + struct GNUNET_NAMESTORE_QueueEntry *add_qe; + + /** + * Response object + */ + json_t *resp_object; + + /** + * The processing state + */ + int state; + + /** + * Handle to NAMESTORE + */ + struct GNUNET_NAMESTORE_Handle *ns_handle; + + /** + * Handle to NAMESTORE it + */ + struct GNUNET_NAMESTORE_ZoneIterator *list_it; + + /** + * Private key for the zone + */ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_pkey; + + /** + * IDENTITY Operation + */ + struct EgoEntry *ego_entry; + + /** + * Ego list + */ + struct EgoEntry *ego_head; + + /** + * Ego list + */ + struct EgoEntry *ego_tail; + + /** + * IDENTITY Operation + */ + struct GNUNET_IDENTITY_Operation *op; + + /** + * Handle to Identity service. + */ + struct GNUNET_IDENTITY_Handle *identity_handle; + + /** + * Rest connection + */ + struct GNUNET_REST_RequestHandle *rest_handle; + + /** + * Desired timeout for the lookup (default is no timeout). + */ + struct GNUNET_TIME_Relative timeout; + + /** + * ID of a task associated with the resolution process. + */ + struct GNUNET_SCHEDULER_Task *timeout_task; + + /** + * The plugin result processor + */ + GNUNET_REST_ResultProcessor proc; + + /** + * The closure of the result processor + */ + void *proc_cls; + + /** + * The url + */ + char *url; + + /** + * Error response message + */ + char *emsg; + + /** + * Response code + */ + int response_code; + +}; + +/** + * Cleanup lookup handle + * @param handle Handle to clean up + */ +static void +cleanup_handle (void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct EgoEntry *ego_tmp; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up\n"); + if (NULL != handle->timeout_task) + { + GNUNET_SCHEDULER_cancel (handle->timeout_task); + handle->timeout_task = NULL; + } + if (NULL != handle->record_name) + GNUNET_free(handle->record_name); + if (NULL != handle->url) + GNUNET_free(handle->url); + if (NULL != handle->emsg) + GNUNET_free(handle->emsg); + if (NULL != handle->rd) + { + if (NULL != handle->rd->data) + GNUNET_free((void*)handle->rd->data); + GNUNET_free(handle->rd); + } + if (NULL != handle->timeout_task) + GNUNET_SCHEDULER_cancel(handle->timeout_task); + if (NULL != handle->list_it) + GNUNET_NAMESTORE_zone_iteration_stop(handle->list_it); + if (NULL != handle->add_qe) + GNUNET_NAMESTORE_cancel(handle->add_qe); + if (NULL != handle->identity_handle) + GNUNET_IDENTITY_disconnect(handle->identity_handle); + if (NULL != handle->ns_handle) + { + GNUNET_NAMESTORE_disconnect(handle->ns_handle); + } + + for (ego_entry = handle->ego_head; + NULL != ego_entry;) + { + ego_tmp = ego_entry; + ego_entry = ego_entry->next; + GNUNET_free(ego_tmp->identifier); + GNUNET_free(ego_tmp->keystring); + GNUNET_free(ego_tmp); + } + + if(NULL != handle->resp_object) + { + json_decref(handle->resp_object); + } + + GNUNET_free (handle); +} + + +/** + * Task run on errors. Reports an error and cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_error (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + json_t *json_error = json_object(); + char *response; + + if (NULL == handle->emsg) + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_ERROR_UNKNOWN); + + json_object_set_new(json_error,"error", json_string(handle->emsg)); + + if (0 == handle->response_code) + handle->response_code = MHD_HTTP_OK; + response = json_dumps (json_error, 0); + resp = GNUNET_REST_create_response (response); + handle->proc (handle->proc_cls, resp, handle->response_code); + json_decref(json_error); + GNUNET_free(response); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + +/** + * Get EgoEntry from list with either a public key or a name + * If public key and name are not NULL, it returns the public key result first + * + * @param handle the RequestHandle + * @param pubkey the public key of an identity (only one can be NULL) + * @param name the name of an identity (only one can be NULL) + * @return EgoEntry or NULL if not found + */ +struct EgoEntry* +get_egoentry_namestore(struct RequestHandle *handle, char *name) +{ + struct EgoEntry *ego_entry; + if (NULL != name) + { + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + { + if (0 != strcasecmp (name, ego_entry->identifier)) + continue; + return ego_entry; + } + } + return NULL; +} + + +/** + * Does internal server error when iteration failed. + * + * @param cls the `struct RequestHandle` + */ +static void +namestore_iteration_error (void *cls) +{ + struct RequestHandle *handle = cls; + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; +} + + +/** + * Create finished callback + * + * @param cls the `struct RequestHandle` + * @param success the success indicating integer, GNUNET_OK on success + * @param emsg the error message (can be NULL) + */ +static void +create_finished (void *cls, int32_t success, const char *emsg) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + + handle->add_qe = NULL; + if (GNUNET_YES != success) + { + if (NULL != emsg) + { + handle->emsg = GNUNET_strdup(emsg); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->emsg = GNUNET_strdup("Error storing records"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + +/** + * Delete finished callback + * + * @param cls the `struct RequestHandle` + * @param success the success indicating integer, GNUNET_OK on success + * @param emsg the error message (can be NULL) + */ +static void +del_finished (void *cls, int32_t success, const char *emsg) +{ + struct RequestHandle *handle = cls; + + handle->add_qe = NULL; + if (GNUNET_NO == success) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup("No record found"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (GNUNET_SYSERR == success) + { + if (NULL != emsg) + { + handle->emsg = GNUNET_strdup(emsg); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->emsg = GNUNET_strdup("Deleting record failed"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->proc (handle->proc_cls, + GNUNET_REST_create_response (NULL), + MHD_HTTP_NO_CONTENT); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + +/** + * Iteration over all results finished, build final + * response. + * + * @param cls the `struct RequestHandle` + */ +static void +namestore_list_finished (void *cls) +{ + struct RequestHandle *handle = cls; + char *result_str; + struct MHD_Response *resp; + + handle->list_it = NULL; + + if (NULL == handle->resp_object) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + result_str = json_dumps (handle->resp_object, 0); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); + resp = GNUNET_REST_create_response (result_str); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free_non_null (result_str); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + +/** + * Create a response with requested records + * + * @param handle the RequestHandle + */ +static void +namestore_list_iteration (void *cls, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, + const char *rname, + unsigned int rd_len, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct RequestHandle *handle = cls; + json_t *record_obj; + + if (NULL == handle->resp_object) + handle->resp_object = json_array(); + + for (unsigned int i = 0; i < rd_len; i++) + { + if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) && + (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)) ) + continue; + + record_obj = GNUNET_JSON_from_gns_record(rname,rd); + + if(NULL == record_obj) + continue; + + json_array_append (handle->resp_object, record_obj); + json_decref (record_obj); + } + + GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1); +} + + +/** + * Handle namestore GET request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +namestore_get (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *egoname; + + egoname = NULL; + ego_entry = NULL; + + //set zone to name if given + if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url)) + { + egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE)+1]; + ego_entry = get_egoentry_namestore(handle, egoname); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + } + if ( NULL != ego_entry ) + { + handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego); + } + if (NULL == handle->zone_pkey) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle, + handle->zone_pkey, + &namestore_iteration_error, + handle, + &namestore_list_iteration, + handle, + &namestore_list_finished, + handle); + if (NULL == handle->list_it) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } +} + + +/** + * Handle namestore POST request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +namestore_add (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct GNUNET_GNSRECORD_Data *gns_record; + struct EgoEntry *ego_entry; + char *egoname; + json_t *data_js; + json_t *name_json; + json_error_t err; + char term_data[handle->rest_handle->data_size + 1]; + + struct GNUNET_JSON_Specification gnsspec[] = { + GNUNET_JSON_spec_gnsrecord_data(&gns_record), + GNUNET_JSON_spec_end () + }; + + if (0 >= handle->rest_handle->data_size) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy(term_data, handle->rest_handle->data, + handle->rest_handle->data_size); + data_js = json_loads (term_data, JSON_DECODE_ANY, &err); + if (GNUNET_OK != GNUNET_JSON_parse (data_js, gnsspec, NULL, NULL)) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + GNUNET_JSON_parse_free(gnsspec); + json_decref (data_js); + return; + } + handle->rd = gns_record; + + name_json = json_object_get(data_js, "record_name"); + if (!json_is_string(name_json)) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + handle->record_name = GNUNET_strdup(json_string_value(name_json)); + if(NULL == handle->record_name) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + if (0 >= strlen(handle->record_name)) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + json_decref (data_js); + return; + } + json_decref (data_js); + + egoname = NULL; + ego_entry = NULL; + + //set zone to name if given + if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url)) + { + egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE)+1]; + ego_entry = get_egoentry_namestore(handle, egoname); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + } + if (NULL != ego_entry) + { + handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego); + } + if (NULL == handle->zone_pkey) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle, + handle->zone_pkey, + handle->record_name, + 1, + handle->rd, + &create_finished, + handle); + if (NULL == handle->add_qe) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } +} + + +/** + * Handle namestore DELETE request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +namestore_delete (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct GNUNET_HashCode key; + struct EgoEntry *ego_entry; + char *egoname; + + egoname = NULL; + ego_entry = NULL; + + //set zone to name if given + if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url)) + { + egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE)+1]; + ego_entry = get_egoentry_namestore(handle, egoname); + + if (NULL == ego_entry) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + } + if ( NULL != ego_entry ) + { + handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego); + } + + GNUNET_CRYPTO_hash ("record_name", strlen ("record_name"), &key); + if ( GNUNET_NO + == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, + &key)) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->record_name = GNUNET_strdup( + GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key)); + + if (NULL == handle->zone_pkey) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle, + handle->zone_pkey, + handle->record_name, + 0, + NULL, + &del_finished, + handle); + if (NULL == handle->add_qe) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } +} + + + +/** + * Respond to OPTIONS request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +options_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct MHD_Response *resp; + struct RequestHandle *handle = cls; + + //independent of path return all options + resp = GNUNET_REST_create_response (NULL); + MHD_add_response_header (resp, + "Access-Control-Allow-Methods", + allow_methods); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); + return; +} + + +/** + * Handle rest request + * + * @param handle the request handle + */ +static void +init_cont (struct RequestHandle *handle) +{ + struct GNUNET_REST_RequestHandlerError err; + static const struct GNUNET_REST_RequestHandler handlers[] = { + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_get}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_add}, + {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete}, + {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont}, + GNUNET_REST_HANDLER_END + }; + + if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, + handlers, + &err, + handle)) + { + handle->response_code = err.error_code; + GNUNET_SCHEDULER_add_now (&do_error, handle); + } +} + +/** + * @param cls closure + * @param ego ego handle + * @param ctx context for application to store data for this ego + * (during the lifetime of this process, initially NULL) + * @param identifier identifier assigned by the user for this ego, + * NULL if the user just deleted the ego and it + * must thus no longer be used + */ +static void +default_ego_cb (void *cls, + struct GNUNET_IDENTITY_Ego *ego, + void **ctx, + const char *identifier) +{ + struct RequestHandle *handle = cls; + handle->op = NULL; + + if (ego != NULL) + { + handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego); + } +} + + +/** + * This function is initially called for all egos and then again + * whenever a ego's identifier changes or if it is deleted. At the + * end of the initial pass over all egos, the function is once called + * with 'NULL' for 'ego'. That does NOT mean that the callback won't + * be invoked in the future or that there was an error. + * + * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', + * this function is only called ONCE, and 'NULL' being passed in + * 'ego' does indicate an error (i.e. name is taken or no default + * value is known). If 'ego' is non-NULL and if '*ctx' + * is set in those callbacks, the value WILL be passed to a subsequent + * call to the identity callback of 'GNUNET_IDENTITY_connect' (if + * that one was not NULL). + * + * When an identity is renamed, this function is called with the + * (known) ego but the NEW identifier. + * + * When an identity is deleted, this function is called with the + * (known) ego and "NULL" for the 'identifier'. In this case, + * the 'ego' is henceforth invalid (and the 'ctx' should also be + * cleaned up). + * + * @param cls closure + * @param ego ego handle + * @param ctx context for application to store data for this ego + * (during the lifetime of this process, initially NULL) + * @param name identifier assigned by the user for this ego, + * NULL if the user just deleted the ego and it + * must thus no longer be used + */ +static void +id_connect_cb (void *cls, + struct GNUNET_IDENTITY_Ego *ego, + void **ctx, + const char *name) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct GNUNET_CRYPTO_EcdsaPublicKey pk; + + if ((NULL == ego) && (NULL == handle->zone_pkey)) + { + handle->op = GNUNET_IDENTITY_get (handle->identity_handle, + "namestore", + &default_ego_cb, + handle); + } + if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state)) + { + handle->state = ID_REST_STATE_POST_INIT; + init_cont (handle); + return; + } + if (ID_REST_STATE_INIT == handle->state) + { + ego_entry = GNUNET_new(struct EgoEntry); + GNUNET_IDENTITY_ego_get_public_key (ego, &pk); + ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); + ego_entry->ego = ego; + GNUNET_asprintf (&ego_entry->identifier, "%s", name); + GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail, + ego_entry); + } + +} + + +/** + * Function processing the REST call + * + * @param method HTTP method + * @param url URL of the HTTP request + * @param data body of the HTTP request (optional) + * @param data_size length of the body + * @param proc callback function for the result + * @param proc_cls closure for callback function + * @return GNUNET_OK if request accepted + */ +static void +rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle, + GNUNET_REST_ResultProcessor proc, + void *proc_cls) +{ + struct RequestHandle *handle = GNUNET_new (struct RequestHandle); + + handle->response_code = 0; + handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; + handle->proc_cls = proc_cls; + handle->proc = proc; + handle->rest_handle = rest_handle; + handle->zone_pkey = NULL; + + handle->url = GNUNET_strdup (rest_handle->url); + if (handle->url[strlen (handle->url)-1] == '/') + handle->url[strlen (handle->url)-1] = '\0'; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); + + handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &id_connect_cb, handle); + handle->ns_handle = GNUNET_NAMESTORE_connect (cfg); + handle->timeout_task = + GNUNET_SCHEDULER_add_delayed (handle->timeout, + &do_error, + handle); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); +} + + +/** + * Entry point for the plugin. + * + * @param cls Config info + * @return NULL on error, otherwise the plugin context + */ +void * +libgnunet_plugin_rest_namestore_init (void *cls) +{ + static struct Plugin plugin; + struct GNUNET_REST_Plugin *api; + + cfg = cls; + if (NULL != plugin.cfg) + return NULL; /* can only initialize once! */ + memset (&plugin, 0, sizeof (struct Plugin)); + plugin.cfg = cfg; + api = GNUNET_new (struct GNUNET_REST_Plugin); + api->cls = &plugin; + api->name = GNUNET_REST_API_NS_NAMESTORE; + api->process_request = &rest_process_request; + GNUNET_asprintf (&allow_methods, + "%s, %s, %s, %s, %s", + MHD_HTTP_METHOD_GET, + MHD_HTTP_METHOD_POST, + MHD_HTTP_METHOD_PUT, + MHD_HTTP_METHOD_DELETE, + MHD_HTTP_METHOD_OPTIONS); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Namestore REST API initialized\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the plugin context (as returned by "init") + * @return always NULL + */ +void * +libgnunet_plugin_rest_namestore_done (void *cls) +{ + struct GNUNET_REST_Plugin *api = cls; + struct Plugin *plugin = api->cls; + plugin->cfg = NULL; + + GNUNET_free_non_null (allow_methods); + GNUNET_free (api); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Namestore REST plugin is finished\n"); + return NULL; +} + +/* end of plugin_rest_namestore.c */ + diff --git a/src/rest-plugins/plugin_rest_openid_connect.c b/src/rest-plugins/plugin_rest_openid_connect.c new file mode 100644 index 000000000..24673c692 --- /dev/null +++ b/src/rest-plugins/plugin_rest_openid_connect.c @@ -0,0 +1,2171 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +/** + * @author Martin Schanzenbach + * @author Philippe Buschmann + * @file identity/plugin_rest_openid_connect.c + * @brief GNUnet Namestore REST plugin + * + */ + +#include "platform.h" +#include "gnunet_rest_plugin.h" +#include "gnunet_identity_service.h" +#include "gnunet_gns_service.h" +#include "gnunet_gnsrecord_lib.h" +#include "gnunet_namestore_service.h" +#include "gnunet_rest_lib.h" +#include "gnunet_jsonapi_lib.h" +#include "gnunet_jsonapi_util.h" +#include "microhttpd.h" +#include +#include +#include "gnunet_signatures.h" +#include "gnunet_reclaim_attribute_lib.h" +#include "gnunet_reclaim_service.h" +#include "oidc_helper.h" + +/** + * REST root namespace + */ +#define GNUNET_REST_API_NS_OIDC "/openid" + +/** + * Authorize endpoint + */ +#define GNUNET_REST_API_NS_AUTHORIZE "/openid/authorize" + +/** + * Token endpoint + */ +#define GNUNET_REST_API_NS_TOKEN "/openid/token" + +/** + * UserInfo endpoint + */ +#define GNUNET_REST_API_NS_USERINFO "/openid/userinfo" + +/** + * Login namespace + */ +#define GNUNET_REST_API_NS_LOGIN "/openid/login" + +/** + * Attribute key + */ +#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE "attribute" + +/** + * Ticket key + */ +#define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket" + + +/** + * Value key + */ +#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE_VALUE "value" + +/** + * State while collecting all egos + */ +#define ID_REST_STATE_INIT 0 + +/** + * Done collecting egos + */ +#define ID_REST_STATE_POST_INIT 1 + +/** + * OIDC grant_type key + */ +#define OIDC_GRANT_TYPE_KEY "grant_type" + +/** + * OIDC grant_type key + */ +#define OIDC_GRANT_TYPE_VALUE "authorization_code" + +/** + * OIDC code key + */ +#define OIDC_CODE_KEY "code" + +/** + * OIDC response_type key + */ +#define OIDC_RESPONSE_TYPE_KEY "response_type" + +/** + * OIDC client_id key + */ +#define OIDC_CLIENT_ID_KEY "client_id" + +/** + * OIDC scope key + */ +#define OIDC_SCOPE_KEY "scope" + +/** + * OIDC redirect_uri key + */ +#define OIDC_REDIRECT_URI_KEY "redirect_uri" + +/** + * OIDC state key + */ +#define OIDC_STATE_KEY "state" + +/** + * OIDC nonce key + */ +#define OIDC_NONCE_KEY "nonce" + +/** + * OIDC cookie header key + */ +#define OIDC_COOKIE_HEADER_KEY "cookie" + +/** + * OIDC cookie header information key + */ +#define OIDC_AUTHORIZATION_HEADER_KEY "authorization" + +/** + * OIDC cookie header information key + */ +#define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity=" + +/** + * OIDC expected response_type while authorizing + */ +#define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code" + +/** + * OIDC expected scope part while authorizing + */ +#define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid" + +/** + * OIDC ignored parameter array + */ +static char* OIDC_ignored_parameter_array [] = +{ + "display", + "prompt", + "ui_locales", + "response_mode", + "id_token_hint", + "login_hint", + "acr_values" +}; + +/** + * OIDC authorized identities and times hashmap + */ +struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time; + +/** + * OIDC authorized identities and times hashmap + */ +struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants; + +/** + * OIDC ticket/code use only once + */ +struct GNUNET_CONTAINER_MultiHashMap *OIDC_ticket_once; + +/** + * OIDC access_token to ticket and ego + */ +struct GNUNET_CONTAINER_MultiHashMap *OIDC_interpret_access_token; + +/** + * The configuration handle + */ +const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * HTTP methods allows for this plugin + */ +static char* allow_methods; + +/** + * @brief struct returned by the initialization function of the plugin + */ +struct Plugin +{ + const struct GNUNET_CONFIGURATION_Handle *cfg; +}; + +/** + * OIDC needed variables + */ +struct OIDC_Variables +{ + /** + * The RP client public key + */ + struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey; + + /** + * The OIDC client id of the RP + */ + char *client_id; + + /** + * The OIDC redirect uri + */ + char *redirect_uri; + + /** + * The list of oidc scopes + */ + char *scope; + + /** + * The OIDC state + */ + char *state; + + /** + * The OIDC nonce + */ + char *nonce; + + /** + * The OIDC response type + */ + char *response_type; + + /** + * The identity chosen by the user to login + */ + char *login_identity; + + /** + * The response JSON + */ + json_t *response; + +}; + +/** + * The ego list + */ +struct EgoEntry +{ + /** + * DLL + */ + struct EgoEntry *next; + + /** + * DLL + */ + struct EgoEntry *prev; + + /** + * Ego Identifier + */ + char *identifier; + + /** + * Public key string + */ + char *keystring; + + /** + * The Ego + */ + struct GNUNET_IDENTITY_Ego *ego; +}; + + +struct RequestHandle +{ + /** + * Ego list + */ + struct EgoEntry *ego_head; + + /** + * Ego list + */ + struct EgoEntry *ego_tail; + + /** + * Selected ego + */ + struct EgoEntry *ego_entry; + + /** + * Pointer to ego private key + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; + + /** + * OIDC variables + */ + struct OIDC_Variables *oidc; + + /** + * The processing state + */ + int state; + + /** + * Handle to Identity service. + */ + struct GNUNET_IDENTITY_Handle *identity_handle; + + /** + * Rest connection + */ + struct GNUNET_REST_RequestHandle *rest_handle; + + /** + * GNS handle + */ + struct GNUNET_GNS_Handle *gns_handle; + + /** + * GNS lookup op + */ + struct GNUNET_GNS_LookupRequest *gns_op; + + /** + * Handle to NAMESTORE + */ + struct GNUNET_NAMESTORE_Handle *namestore_handle; + + /** + * Iterator for NAMESTORE + */ + struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it; + + /** + * Attribute claim list + */ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list; + + /** + * IDENTITY Operation + */ + struct GNUNET_IDENTITY_Operation *op; + + /** + * Identity Provider + */ + struct GNUNET_RECLAIM_Handle *idp; + + /** + * Idp Operation + */ + struct GNUNET_RECLAIM_Operation *idp_op; + + /** + * Attribute iterator + */ + struct GNUNET_RECLAIM_AttributeIterator *attr_it; + + /** + * Ticket iterator + */ + struct GNUNET_RECLAIM_TicketIterator *ticket_it; + + /** + * A ticket + */ + struct GNUNET_RECLAIM_Ticket ticket; + + /** + * Desired timeout for the lookup (default is no timeout). + */ + struct GNUNET_TIME_Relative timeout; + + /** + * ID of a task associated with the resolution process. + */ + struct GNUNET_SCHEDULER_Task *timeout_task; + + /** + * The plugin result processor + */ + GNUNET_REST_ResultProcessor proc; + + /** + * The closure of the result processor + */ + void *proc_cls; + + /** + * The url + */ + char *url; + + /** + * The tld for redirect + */ + char *tld; + + /** + * The redirect prefix + */ + char *redirect_prefix; + + /** + * The redirect suffix + */ + char *redirect_suffix; + + /** + * Error response message + */ + char *emsg; + + /** + * Error response description + */ + char *edesc; + + /** + * Reponse code + */ + int response_code; + + /** + * Response object + */ + struct GNUNET_JSONAPI_Document *resp_object; + +}; + +/** + * Cleanup lookup handle + * @param handle Handle to clean up + */ +static void +cleanup_handle (struct RequestHandle *handle) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp; + struct EgoEntry *ego_entry; + struct EgoEntry *ego_tmp; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up\n"); + if (NULL != handle->resp_object) + GNUNET_JSONAPI_document_delete (handle->resp_object); + if (NULL != handle->timeout_task) + GNUNET_SCHEDULER_cancel (handle->timeout_task); + if (NULL != handle->identity_handle) + GNUNET_IDENTITY_disconnect (handle->identity_handle); + if (NULL != handle->attr_it) + GNUNET_RECLAIM_get_attributes_stop (handle->attr_it); + if (NULL != handle->ticket_it) + GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it); + if (NULL != handle->idp) + GNUNET_RECLAIM_disconnect (handle->idp); + if (NULL != handle->url) + GNUNET_free (handle->url); + if (NULL != handle->tld) + GNUNET_free (handle->tld); + if (NULL != handle->redirect_prefix) + GNUNET_free (handle->redirect_prefix); + if (NULL != handle->redirect_suffix) + GNUNET_free (handle->redirect_suffix); + if (NULL != handle->emsg) + GNUNET_free (handle->emsg); + if (NULL != handle->edesc) + GNUNET_free (handle->edesc); + if (NULL != handle->gns_op) + GNUNET_GNS_lookup_cancel (handle->gns_op); + if (NULL != handle->gns_handle) + GNUNET_GNS_disconnect (handle->gns_handle); + + if (NULL != handle->namestore_handle) + GNUNET_NAMESTORE_disconnect (handle->namestore_handle); + if (NULL != handle->oidc) + { + if (NULL != handle->oidc->client_id) + GNUNET_free(handle->oidc->client_id); + if (NULL != handle->oidc->login_identity) + GNUNET_free(handle->oidc->login_identity); + if (NULL != handle->oidc->nonce) + GNUNET_free(handle->oidc->nonce); + if (NULL != handle->oidc->redirect_uri) + GNUNET_free(handle->oidc->redirect_uri); + if (NULL != handle->oidc->response_type) + GNUNET_free(handle->oidc->response_type); + if (NULL != handle->oidc->scope) + GNUNET_free(handle->oidc->scope); + if (NULL != handle->oidc->state) + GNUNET_free(handle->oidc->state); + if (NULL != handle->oidc->response) + json_decref(handle->oidc->response); + GNUNET_free(handle->oidc); + } + if ( NULL != handle->attr_list ) + { + for (claim_entry = handle->attr_list->list_head; + NULL != claim_entry;) + { + claim_tmp = claim_entry; + claim_entry = claim_entry->next; + GNUNET_free(claim_tmp->claim); + GNUNET_free(claim_tmp); + } + GNUNET_free (handle->attr_list); + } + for (ego_entry = handle->ego_head; + NULL != ego_entry;) + { + ego_tmp = ego_entry; + ego_entry = ego_entry->next; + GNUNET_free (ego_tmp->identifier); + GNUNET_free (ego_tmp->keystring); + GNUNET_free (ego_tmp); + } + if (NULL != handle->attr_it) + { + GNUNET_free(handle->attr_it); + } + GNUNET_free (handle); +} + +static void +cleanup_handle_delayed (void *cls) +{ + cleanup_handle (cls); +} + + +/** + * Task run on error, sends error message. Cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_error (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + char *json_error; + + GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}", + handle->emsg, + (NULL != handle->edesc) ? handle->edesc : "", + (NULL != handle->oidc->state) ? ", \"state\":\"" : "", + (NULL != handle->oidc->state) ? handle->oidc->state : "", + (NULL != handle->oidc->state) ? "\"" : ""); + if ( 0 == handle->response_code ) + { + handle->response_code = MHD_HTTP_BAD_REQUEST; + } + resp = GNUNET_REST_create_response (json_error); + if (MHD_HTTP_UNAUTHORIZED == handle->response_code) + { + MHD_add_response_header(resp, "WWW-Authenticate", "Basic"); + } + MHD_add_response_header (resp, "Content-Type", "application/json"); + handle->proc (handle->proc_cls, resp, handle->response_code); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); + GNUNET_free (json_error); +} + + +/** + * Task run on error in userinfo endpoint, sends error header. Cleans up + * everything + * + * @param cls the `struct RequestHandle` + */ +static void +do_userinfo_error (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + char *error; + + GNUNET_asprintf (&error, "error=\"%s\", error_description=\"%s\"", + handle->emsg, + (NULL != handle->edesc) ? handle->edesc : ""); + resp = GNUNET_REST_create_response (""); + MHD_add_response_header(resp, "WWW-Authenticate", error); + handle->proc (handle->proc_cls, resp, handle->response_code); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); + GNUNET_free (error); +} + + +/** + * Task run on error, sends error message and redirects. Cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_redirect_error (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + char* redirect; + GNUNET_asprintf (&redirect, + "%s?error=%s&error_description=%s%s%s", + handle->oidc->redirect_uri, handle->emsg, handle->edesc, + (NULL != handle->oidc->state) ? "&state=" : "", + (NULL != handle->oidc->state) ? handle->oidc->state : ""); + resp = GNUNET_REST_create_response (""); + MHD_add_response_header (resp, "Location", redirect); + handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); + GNUNET_free (redirect); +} + +/** + * Task run on timeout, sends error message. Cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_timeout (void *cls) +{ + struct RequestHandle *handle = cls; + + handle->timeout_task = NULL; + do_error (handle); +} + +/** + * Return attributes for claim + * + * @param cls the request handle + */ +static void +return_userinfo_response (void *cls) +{ + char* result_str; + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + + result_str = json_dumps (handle->oidc->response, 0); + + resp = GNUNET_REST_create_response (result_str); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free (result_str); + cleanup_handle (handle); +} + +/** + * Returns base64 encoded string without padding + * + * @param string the string to encode + * @return base64 encoded string + */ +static char* +base_64_encode(const char *s) +{ + char *enc; + char *tmp; + + GNUNET_STRINGS_base64_encode(s, strlen(s), &enc); + tmp = strrchr (enc, '='); + *tmp = '\0'; + return enc; +} + +/** + * Respond to OPTIONS request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +options_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct MHD_Response *resp; + struct RequestHandle *handle = cls; + + //For now, independent of path return all options + resp = GNUNET_REST_create_response (NULL); + MHD_add_response_header (resp, + "Access-Control-Allow-Methods", + allow_methods); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + cleanup_handle (handle); + return; +} + +/** + * Interprets cookie header and pass its identity keystring to handle + */ +static void +cookie_identity_interpretation (struct RequestHandle *handle) +{ + struct GNUNET_HashCode cache_key; + char *cookies; + struct GNUNET_TIME_Absolute current_time, *relog_time; + char delimiter[] = "; "; + + //gets identity of login try with cookie + GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY), + &cache_key); + if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map, + &cache_key) ) + { + //splits cookies and find 'Identity' cookie + cookies = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key); + handle->oidc->login_identity = strtok(cookies, delimiter); + + while ( NULL != handle->oidc->login_identity ) + { + if ( NULL != strstr (handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY) ) + { + break; + } + handle->oidc->login_identity = strtok (NULL, delimiter); + } + GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen (handle->oidc->login_identity), + &cache_key); + if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, &cache_key) ) + { + relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time, + &cache_key); + current_time = GNUNET_TIME_absolute_get (); + // 30 min after old login -> redirect to login + if ( current_time.abs_value_us <= relog_time->abs_value_us ) + { + handle->oidc->login_identity = strtok(handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY); + handle->oidc->login_identity = GNUNET_strdup(handle->oidc->login_identity); + } else { + handle->oidc->login_identity = NULL; + } + } + else + { + handle->oidc->login_identity = NULL; + } + } +} + +/** + * Redirects to login page stored in configuration file + */ +static void +login_redirection(void *cls) +{ + char *login_base_url; + char *new_redirect; + struct MHD_Response *resp; + struct RequestHandle *handle = cls; + + if ( GNUNET_OK + == GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin", + "address", &login_base_url) ) + { + GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s", + login_base_url, + OIDC_RESPONSE_TYPE_KEY, + handle->oidc->response_type, + OIDC_CLIENT_ID_KEY, + handle->oidc->client_id, + OIDC_REDIRECT_URI_KEY, + handle->oidc->redirect_uri, + OIDC_SCOPE_KEY, + handle->oidc->scope, + OIDC_STATE_KEY, + (NULL != handle->oidc->state) ? handle->oidc->state : "", + OIDC_NONCE_KEY, + (NULL != handle->oidc->nonce) ? handle->oidc->nonce : ""); + resp = GNUNET_REST_create_response (""); + MHD_add_response_header (resp, "Location", new_redirect); + GNUNET_free(login_base_url); + } + else + { + handle->emsg = GNUNET_strdup("server_error"); + handle->edesc = GNUNET_strdup ("gnunet configuration failed"); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); + GNUNET_free(new_redirect); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); +} + +/** + * Does internal server error when iteration failed. + */ +static void +oidc_iteration_error (void *cls) +{ + struct RequestHandle *handle = cls; + handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR"); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_SCHEDULER_add_now (&do_error, handle); +} + +static void +get_client_name_result (void *cls, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, + const char *label, + unsigned int rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + char *ticket_str; + char *redirect_uri; + char *code_json_string; + char *code_base64_final_string; + + ticket_str = GNUNET_STRINGS_data_to_string_alloc (&handle->ticket, + sizeof (struct GNUNET_RECLAIM_Ticket)); + //TODO change if more attributes are needed (see max_age) + code_json_string = OIDC_build_authz_code (&handle->priv_key, + &handle->ticket, + handle->oidc->nonce); + code_base64_final_string = base_64_encode(code_json_string); + GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s", + handle->redirect_prefix, + handle->tld, + handle->redirect_suffix, + handle->oidc->response_type, + code_base64_final_string, handle->oidc->state); + resp = GNUNET_REST_create_response (""); + MHD_add_response_header (resp, "Location", redirect_uri); + handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); + GNUNET_free (redirect_uri); + GNUNET_free (ticket_str); + GNUNET_free (code_json_string); + GNUNET_free (code_base64_final_string); + return; + +} + + +static void +get_client_name_error (void *cls) +{ + struct RequestHandle *handle = cls; + + handle->emsg = GNUNET_strdup("server_error"); + handle->edesc = GNUNET_strdup("Server cannot generate ticket, no name found for client."); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); +} + + +static void +lookup_redirect_uri_result (void *cls, + uint32_t rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct RequestHandle *handle = cls; + char *tmp; + char *tmp_key_str; + char *pos; + struct GNUNET_CRYPTO_EcdsaPublicKey redirect_zone; + + handle->gns_op = NULL; + if (0 == rd_count) + { + handle->emsg = GNUNET_strdup("server_error"); + handle->edesc = GNUNET_strdup("Server cannot generate ticket, redirect uri not found."); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + for (int i = 0; i < rd_count; i++) + { + if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type) + continue; + if (0 != strcmp (rd[i].data, + handle->oidc->redirect_uri)) + continue; + tmp = GNUNET_strdup (rd[i].data); + pos = strrchr (tmp, + (unsigned char) '.'); + *pos = '\0'; + handle->redirect_prefix = GNUNET_strdup (tmp); + tmp_key_str = pos + 1; + pos = strchr (tmp_key_str, + (unsigned char) '/'); + *pos = '\0'; + handle->redirect_suffix = GNUNET_strdup (pos + 1); + + GNUNET_STRINGS_string_to_data (tmp_key_str, + strlen (tmp_key_str), + &redirect_zone, + sizeof (redirect_zone)); + + GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle, + &handle->priv_key, + &redirect_zone, + &get_client_name_error, + handle, + &get_client_name_result, + handle); + GNUNET_free (tmp); + return; + } + handle->emsg = GNUNET_strdup("server_error"); + handle->edesc = GNUNET_strdup("Server cannot generate ticket, redirect uri not found."); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); +} + +/** + * Issues ticket and redirects to relying party with the authorization code as + * parameter. Otherwise redirects with error + */ +static void +oidc_ticket_issue_cb (void* cls, + const struct GNUNET_RECLAIM_Ticket *ticket) +{ + struct RequestHandle *handle = cls; + + handle->idp_op = NULL; + handle->ticket = *ticket; + if (NULL == ticket) + { + handle->emsg = GNUNET_strdup("server_error"); + handle->edesc = GNUNET_strdup("Server cannot generate ticket."); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + handle->gns_op = GNUNET_GNS_lookup (handle->gns_handle, + "+", + &handle->oidc->client_pkey, + GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT, + GNUNET_GNS_LO_DEFAULT, + &lookup_redirect_uri_result, + handle); + +} + +static void +oidc_collect_finished_cb (void *cls) +{ + struct RequestHandle *handle = cls; + handle->attr_it = NULL; + handle->ticket_it = NULL; + if (NULL == handle->attr_list->list_head) + { + handle->emsg = GNUNET_strdup("invalid_scope"); + handle->edesc = GNUNET_strdup("The requested scope is not available."); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp, + &handle->priv_key, + &handle->oidc->client_pkey, + handle->attr_list, + &oidc_ticket_issue_cb, + handle); +} + + +/** + * Collects all attributes for an ego if in scope parameter + */ +static void +oidc_attr_collect (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) +{ + struct RequestHandle *handle = cls; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + char* scope_variables; + char* scope_variable; + char delimiter[]=" "; + + if ( (NULL == attr->name) || (NULL == attr->data) ) + { + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + return; + } + + scope_variables = GNUNET_strdup(handle->oidc->scope); + scope_variable = strtok (scope_variables, delimiter); + while (NULL != scope_variable) + { + if ( 0 == strcmp (attr->name, scope_variable) ) + { + break; + } + scope_variable = strtok (NULL, delimiter); + } + if ( NULL == scope_variable ) + { + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + GNUNET_free(scope_variables); + return; + } + GNUNET_free(scope_variables); + + le = GNUNET_new(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name, attr->type, + attr->data, attr->data_size); + GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head, + handle->attr_list->list_tail, le); + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); +} + + +/** + * Checks time and cookie and redirects accordingly + */ +static void +login_check (void *cls) +{ + struct RequestHandle *handle = cls; + struct GNUNET_TIME_Absolute current_time, *relog_time; + struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey; + struct GNUNET_HashCode cache_key; + char *identity_cookie; + + GNUNET_asprintf (&identity_cookie, "Identity=%s", handle->oidc->login_identity); + GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key); + GNUNET_free(identity_cookie); + //No login time for identity -> redirect to login + if ( GNUNET_YES + == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, + &cache_key) ) + { + relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time, + &cache_key); + current_time = GNUNET_TIME_absolute_get (); + // 30 min after old login -> redirect to login + if ( current_time.abs_value_us <= relog_time->abs_value_us ) + { + if ( GNUNET_OK + != GNUNET_CRYPTO_ecdsa_public_key_from_string ( + handle->oidc->login_identity, + strlen (handle->oidc->login_identity), &pubkey) ) + { + handle->emsg = GNUNET_strdup("invalid_cookie"); + handle->edesc = GNUNET_strdup( + "The cookie of a login identity is not valid"); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + // iterate over egos and compare their public key + for (handle->ego_entry = handle->ego_head; + NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next) + { + GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey); + if ( 0 + == memcmp (&ego_pkey, &pubkey, + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) + { + handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key ( + handle->ego_entry->ego); + handle->resp_object = GNUNET_JSONAPI_document_new (); + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->attr_list = GNUNET_new( + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); + handle->attr_it = GNUNET_RECLAIM_get_attributes_start ( + handle->idp, &handle->priv_key, &oidc_iteration_error, handle, + &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle); + return; + } + } + //handle->emsg = GNUNET_strdup("invalid_cookie"); + //handle->edesc = GNUNET_strdup( + // "The cookie of the login identity is not valid"); + //GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + GNUNET_SCHEDULER_add_now (&login_redirection,handle); + return; + } + } +} + +/** + * Iteration over all results finished, build final + * response. + * + * @param cls the `struct RequestHandle` + */ +static void +build_authz_response (void *cls) +{ + struct RequestHandle *handle = cls; + struct GNUNET_HashCode cache_key; + + char *expected_scope; + char delimiter[]=" "; + int number_of_ignored_parameter, iterator; + + + // REQUIRED value: redirect_uri + GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY), + &cache_key); + if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &cache_key)) + { + handle->emsg=GNUNET_strdup("invalid_request"); + handle->edesc=GNUNET_strdup("missing parameter redirect_uri"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->oidc->redirect_uri = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, + &cache_key)); + + // REQUIRED value: response_type + GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY), + &cache_key); + if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &cache_key)) + { + handle->emsg=GNUNET_strdup("invalid_request"); + handle->edesc=GNUNET_strdup("missing parameter response_type"); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, + &cache_key); + handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type); + + // REQUIRED value: scope + GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key); + if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &cache_key)) + { + handle->emsg=GNUNET_strdup("invalid_request"); + handle->edesc=GNUNET_strdup("missing parameter scope"); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, + &cache_key); + handle->oidc->scope = GNUNET_strdup(handle->oidc->scope); + + //OPTIONAL value: nonce + GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key); + if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &cache_key)) + { + handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, + &cache_key); + handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce); + } + + //TODO check other values if needed + number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *); + for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ ) + { + GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator], + strlen(OIDC_ignored_parameter_array[iterator]), + &cache_key); + if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map, + &cache_key)) + { + handle->emsg=GNUNET_strdup("access_denied"); + GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s", + OIDC_ignored_parameter_array[iterator]); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + } + + // Checks if response_type is 'code' + if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) ) + { + handle->emsg=GNUNET_strdup("unsupported_response_type"); + handle->edesc=GNUNET_strdup("The authorization server does not support " + "obtaining this authorization code."); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + + // Checks if scope contains 'openid' + expected_scope = GNUNET_strdup(handle->oidc->scope); + char* test; + test = strtok (expected_scope, delimiter); + while (NULL != test) + { + if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) ) + { + break; + } + test = strtok (NULL, delimiter); + } + if (NULL == test) + { + handle->emsg = GNUNET_strdup("invalid_scope"); + handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or " + "malformed."); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + GNUNET_free(expected_scope); + return; + } + + GNUNET_free(expected_scope); + + if( NULL != handle->oidc->login_identity ) + { + GNUNET_SCHEDULER_add_now(&login_check,handle); + return; + } + + GNUNET_SCHEDULER_add_now(&login_redirection,handle); +} + +/** + * Responds to authorization GET and url-encoded POST request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct GNUNET_HashCode cache_key; + struct EgoEntry *tmp_ego; + const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; + struct GNUNET_CRYPTO_EcdsaPublicKey pkey; + + cookie_identity_interpretation(handle); + + //RECOMMENDED value: state - REQUIRED for answers + GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key); + if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &cache_key)) + { + handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, + &cache_key); + handle->oidc->state = GNUNET_strdup (handle->oidc->state); + } + + // REQUIRED value: client_id + GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY), + &cache_key); + if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &cache_key)) + { + handle->emsg=GNUNET_strdup("invalid_request"); + handle->edesc=GNUNET_strdup("missing parameter client_id"); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->oidc->client_id = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, + &cache_key)); + + if ( GNUNET_OK + != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id, + strlen (handle->oidc->client_id), + &handle->oidc->client_pkey) ) + { + handle->emsg = GNUNET_strdup("unauthorized_client"); + handle->edesc = GNUNET_strdup("The client is not authorized to request an " + "authorization code using this method."); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + + if ( NULL == handle->ego_head ) + { + handle->emsg = GNUNET_strdup("server_error"); + handle->edesc = GNUNET_strdup ("Egos are missing"); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + handle->ego_entry = handle->ego_head; + handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego); + //If we know this identity, translated the corresponding TLD + //TODO: We might want to have a reverse lookup functionality for TLDs? + for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next) + { + priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego); + GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, + &pkey); + if ( 0 == memcmp (&pkey, &handle->oidc->client_pkey, + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) + { + handle->tld = GNUNET_strdup (tmp_ego->identifier); + handle->ego_entry = handle->ego_tail; + } + } + GNUNET_SCHEDULER_add_now (&build_authz_response, handle); +} + +/** + * Combines an identity with a login time and responds OK to login request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +login_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct MHD_Response *resp = GNUNET_REST_create_response (""); + struct RequestHandle *handle = cls; + struct GNUNET_HashCode cache_key; + struct GNUNET_TIME_Absolute *current_time; + struct GNUNET_TIME_Absolute *last_time; + char* cookie; + json_t *root; + json_error_t error; + json_t *identity; + char term_data[handle->rest_handle->data_size+1]; + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, handle->rest_handle->data, handle->rest_handle->data_size); + root = json_loads (term_data, JSON_DECODE_ANY, &error); + identity = json_object_get (root, "identity"); + if ( json_is_string(identity) ) + { + GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity)); + MHD_add_response_header (resp, "Set-Cookie", cookie); + MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST"); + GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key); + + current_time = GNUNET_new(struct GNUNET_TIME_Absolute); + *current_time = GNUNET_TIME_relative_to_absolute ( + GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (), + 5)); + last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key); + if (NULL != last_time) + { + GNUNET_free(last_time); + } + GNUNET_CONTAINER_multihashmap_put ( + OIDC_identity_login_time, &cache_key, current_time, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); + + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free(cookie); + } + else + { + handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST); + } + json_decref (root); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); + return; +} + +static int +check_authorization (struct RequestHandle *handle, + struct GNUNET_CRYPTO_EcdsaPublicKey *cid) +{ + struct GNUNET_HashCode cache_key; + char *authorization; + char *credentials; + char *basic_authorization; + char *client_id; + char *pass; + char *expected_pass; + int client_exists = GNUNET_NO; + + GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, + strlen (OIDC_AUTHORIZATION_HEADER_KEY), + &cache_key); + if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map, + &cache_key) ) + { + handle->emsg=GNUNET_strdup("invalid_client"); + handle->edesc=GNUNET_strdup("missing authorization"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + return GNUNET_SYSERR; + } + authorization = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map, + &cache_key); + + //split header in "Basic" and [content] + credentials = strtok (authorization, " "); + if (0 != strcmp ("Basic", credentials)) + { + handle->emsg=GNUNET_strdup("invalid_client"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + return GNUNET_SYSERR; + } + credentials = strtok(NULL, " "); + if (NULL == credentials) + { + handle->emsg=GNUNET_strdup("invalid_client"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + return GNUNET_SYSERR; + } + GNUNET_STRINGS_base64_decode (credentials, + strlen (credentials), + (void**)&basic_authorization); + + if ( NULL == basic_authorization ) + { + handle->emsg=GNUNET_strdup("invalid_client"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + return GNUNET_SYSERR; + } + client_id = strtok (basic_authorization, ":"); + if ( NULL == client_id ) + { + GNUNET_free_non_null(basic_authorization); + handle->emsg=GNUNET_strdup("invalid_client"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + return GNUNET_SYSERR; + } + pass = strtok (NULL, ":"); + if (NULL == pass) + { + GNUNET_free_non_null(basic_authorization); + handle->emsg=GNUNET_strdup("invalid_client"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + return GNUNET_SYSERR; + } + + //check client password + if ( GNUNET_OK + == GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin", + "psw", &expected_pass) ) + { + if (0 != strcmp (expected_pass, pass)) + { + GNUNET_free_non_null(basic_authorization); + GNUNET_free(expected_pass); + handle->emsg=GNUNET_strdup("invalid_client"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + return GNUNET_SYSERR; + } + GNUNET_free(expected_pass); + } + else + { + GNUNET_free_non_null(basic_authorization); + handle->emsg = GNUNET_strdup("server_error"); + handle->edesc = GNUNET_strdup ("gnunet configuration failed"); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + return GNUNET_SYSERR; + } + + //check client_id + for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; ) + { + if ( 0 == strcmp(handle->ego_entry->keystring, client_id)) + { + client_exists = GNUNET_YES; + break; + } + handle->ego_entry = handle->ego_entry->next; + } + if (GNUNET_NO == client_exists) + { + GNUNET_free_non_null(basic_authorization); + handle->emsg=GNUNET_strdup("invalid_client"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + return GNUNET_SYSERR; + } + GNUNET_STRINGS_string_to_data (client_id, + strlen(client_id), + cid, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + + GNUNET_free (basic_authorization); + return GNUNET_OK; +} + +static int +ego_exists (struct RequestHandle *handle, + struct GNUNET_CRYPTO_EcdsaPublicKey *test_key) +{ + struct EgoEntry *ego_entry; + struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; + + for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) + { + GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key); + if (0 == memcmp (&pub_key, + test_key, + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) + { + break; + } + } + if (NULL == ego_entry) + return GNUNET_NO; + return GNUNET_YES; +} + +static void +store_ticket_reference (const struct RequestHandle *handle, + const char* access_token, + const struct GNUNET_RECLAIM_Ticket *ticket, + const struct GNUNET_CRYPTO_EcdsaPublicKey *cid) +{ + struct GNUNET_HashCode cache_key; + char *id_ticket_combination; + char *ticket_string; + char *client_id; + + GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key); + client_id = GNUNET_STRINGS_data_to_string_alloc (cid, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + ticket_string = GNUNET_STRINGS_data_to_string_alloc (ticket, + sizeof (struct GNUNET_RECLAIM_Ticket)); + GNUNET_asprintf(&id_ticket_combination, + "%s;%s", + client_id, + ticket_string); + GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token, + &cache_key, + id_ticket_combination, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); + + GNUNET_free (client_id); + GNUNET_free (ticket_string); +} + +/** + * Responds to token url-encoded POST request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct GNUNET_TIME_Relative expiration_time; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *cl; + struct GNUNET_RECLAIM_Ticket *ticket; + struct GNUNET_CRYPTO_EcdsaPublicKey cid; + struct GNUNET_HashCode cache_key; + struct MHD_Response *resp; + char *grant_type; + char *code; + char *json_response; + char *id_token; + char *access_token; + char *jwt_secret; + char *nonce; + int i = 1; + + /* + * Check Authorization + */ + if (GNUNET_SYSERR == check_authorization (handle, + &cid)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "OIDC authorization for token endpoint failed\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + /* + * Check parameter + */ + + //TODO Do not allow multiple equal parameter names + //REQUIRED grant_type + GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), &cache_key); + if (GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &cache_key)) + { + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("missing parameter grant_type"); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + grant_type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, + &cache_key); + + //REQUIRED code + GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key); + if (GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &cache_key)) + { + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("missing parameter code"); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + code = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, + &cache_key); + + //REQUIRED redirect_uri + GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY), + &cache_key); + if (GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &cache_key) ) + { + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("missing parameter redirect_uri"); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + //Check parameter grant_type == "authorization_code" + if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type)) + { + handle->emsg=GNUNET_strdup("unsupported_grant_type"); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + GNUNET_CRYPTO_hash (code, strlen (code), &cache_key); + if (GNUNET_SYSERR == + GNUNET_CONTAINER_multihashmap_put (OIDC_ticket_once, + &cache_key, + &i, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) ) + { + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("Cannot use the same code more than once"); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + //decode code + if(GNUNET_OK != OIDC_parse_authz_code (&cid, + code, + &ticket, + &nonce)) + { + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("invalid code"); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + //create jwt + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time(cfg, + "reclaim-rest-plugin", + "expiration_time", + &expiration_time)) + { + handle->emsg = GNUNET_strdup("server_error"); + handle->edesc = GNUNET_strdup ("gnunet configuration failed"); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_SCHEDULER_add_now (&do_error, handle); + GNUNET_free(ticket); + return; + } + + + //TODO OPTIONAL acr,amr,azp + if (GNUNET_NO == ego_exists (handle, + &ticket->audience)) + { + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("invalid code..."); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + GNUNET_free(ticket); + } + if ( GNUNET_OK + != GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin", + "jwt_secret", &jwt_secret) ) + { + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("No signing secret configured!"); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_SCHEDULER_add_now (&do_error, handle); + GNUNET_free(ticket); + return; + } + //TODO We should collect the attributes here. cl always empty + cl = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); + id_token = OIDC_id_token_new (&ticket->audience, + &ticket->identity, + cl, + &expiration_time, + (NULL != nonce) ? nonce : NULL, + jwt_secret); + access_token = OIDC_access_token_new (); + OIDC_build_token_response (access_token, + id_token, + &expiration_time, + &json_response); + + store_ticket_reference (handle, + access_token, + ticket, + &cid); + resp = GNUNET_REST_create_response (json_response); + MHD_add_response_header (resp, "Cache-Control", "no-store"); + MHD_add_response_header (resp, "Pragma", "no-cache"); + MHD_add_response_header (resp, "Content-Type", "application/json"); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_RECLAIM_ATTRIBUTE_list_destroy(cl); + GNUNET_free(access_token); + GNUNET_free(json_response); + GNUNET_free(ticket); + GNUNET_free(id_token); + GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle); +} + +/** + * Collects claims and stores them in handle + */ +static void +consume_ticket (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) +{ + struct RequestHandle *handle = cls; + char *tmp_value; + json_t *value; + + if (NULL == identity) + { + GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle); + return; + } + + tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, + attr->data, + attr->data_size); + + value = json_string (tmp_value); + + + json_object_set_new (handle->oidc->response, + attr->name, + value); + GNUNET_free (tmp_value); +} + +/** + * Responds to userinfo GET and url-encoded POST request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, void *cls) +{ + //TODO expiration time + struct RequestHandle *handle = cls; + char delimiter[] = " "; + char delimiter_db[] = ";"; + struct GNUNET_HashCode cache_key; + char *authorization, *authorization_type, *authorization_access_token; + char *client_ticket, *client, *ticket_str; + struct GNUNET_RECLAIM_Ticket *ticket; + + GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, + strlen (OIDC_AUTHORIZATION_HEADER_KEY), + &cache_key); + if ( GNUNET_NO + == GNUNET_CONTAINER_multihashmap_contains ( + handle->rest_handle->header_param_map, &cache_key) ) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("No Access Token"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + return; + } + authorization = GNUNET_CONTAINER_multihashmap_get ( + handle->rest_handle->header_param_map, &cache_key); + + //split header in "Bearer" and access_token + authorization = GNUNET_strdup(authorization); + authorization_type = strtok (authorization, delimiter); + if ( 0 != strcmp ("Bearer", authorization_type) ) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("No Access Token"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + GNUNET_free(authorization); + return; + } + authorization_access_token = strtok (NULL, delimiter); + if ( NULL == authorization_access_token ) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("No Access Token"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + GNUNET_free(authorization); + return; + } + + GNUNET_CRYPTO_hash (authorization_access_token, + strlen (authorization_access_token), + &cache_key); + if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_interpret_access_token, + &cache_key) ) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("The Access Token expired"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + GNUNET_free(authorization); + return; + } + + client_ticket = GNUNET_CONTAINER_multihashmap_get(OIDC_interpret_access_token, + &cache_key); + client_ticket = GNUNET_strdup(client_ticket); + client = strtok(client_ticket,delimiter_db); + if (NULL == client) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("The Access Token expired"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + GNUNET_free(authorization); + GNUNET_free(client_ticket); + return; + } + handle->ego_entry = handle->ego_head; + for(; NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next) + { + if (0 == strcmp(handle->ego_entry->keystring,client)) + { + break; + } + } + if (NULL == handle->ego_entry) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("The Access Token expired"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + GNUNET_free(authorization); + GNUNET_free(client_ticket); + return; + } + ticket_str = strtok(NULL, delimiter_db); + if (NULL == ticket_str) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("The Access Token expired"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + GNUNET_free(authorization); + GNUNET_free(client_ticket); + return; + } + ticket = GNUNET_new(struct GNUNET_RECLAIM_Ticket); + if ( GNUNET_OK + != GNUNET_STRINGS_string_to_data (ticket_str, + strlen (ticket_str), + ticket, + sizeof(struct GNUNET_RECLAIM_Ticket))) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("The Access Token expired"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + GNUNET_free(ticket); + GNUNET_free(authorization); + GNUNET_free(client_ticket); + return; + } + + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->oidc->response = json_object(); + json_object_set_new( handle->oidc->response, "sub", json_string( handle->ego_entry->keystring)); + handle->idp_op = GNUNET_RECLAIM_ticket_consume ( + handle->idp, + GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego), + ticket, + consume_ticket, + handle); + GNUNET_free(ticket); + GNUNET_free(authorization); + GNUNET_free(client_ticket); + +} + + +/** + * Handle rest request + * + * @param handle the request handle + */ +static void +init_cont (struct RequestHandle *handle) +{ + struct GNUNET_REST_RequestHandlerError err; + static const struct GNUNET_REST_RequestHandler handlers[] = { + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, //url-encoded + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint }, + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, + {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, + &options_cont}, + GNUNET_REST_HANDLER_END + }; + + if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, + handlers, + &err, + handle)) + { + handle->response_code = err.error_code; + GNUNET_SCHEDULER_add_now (&do_error, handle); + } +} + +/** + * If listing is enabled, prints information about the egos. + * + * This function is initially called for all egos and then again + * whenever a ego's identifier changes or if it is deleted. At the + * end of the initial pass over all egos, the function is once called + * with 'NULL' for 'ego'. That does NOT mean that the callback won't + * be invoked in the future or that there was an error. + * + * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', + * this function is only called ONCE, and 'NULL' being passed in + * 'ego' does indicate an error (i.e. name is taken or no default + * value is known). If 'ego' is non-NULL and if '*ctx' + * is set in those callbacks, the value WILL be passed to a subsequent + * call to the identity callback of 'GNUNET_IDENTITY_connect' (if + * that one was not NULL). + * + * When an identity is renamed, this function is called with the + * (known) ego but the NEW identifier. + * + * When an identity is deleted, this function is called with the + * (known) ego and "NULL" for the 'identifier'. In this case, + * the 'ego' is henceforth invalid (and the 'ctx' should also be + * cleaned up). + * + * @param cls closure + * @param ego ego handle + * @param ctx context for application to store data for this ego + * (during the lifetime of this process, initially NULL) + * @param identifier identifier assigned by the user for this ego, + * NULL if the user just deleted the ego and it + * must thus no longer be used + */ +static void +list_ego (void *cls, + struct GNUNET_IDENTITY_Ego *ego, + void **ctx, + const char *identifier) +{ + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct GNUNET_CRYPTO_EcdsaPublicKey pk; + + if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state)) + { + handle->state = ID_REST_STATE_POST_INIT; + init_cont (handle); + return; + } + if (ID_REST_STATE_INIT == handle->state) { + ego_entry = GNUNET_new (struct EgoEntry); + GNUNET_IDENTITY_ego_get_public_key (ego, &pk); + ego_entry->keystring = + GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); + ego_entry->ego = ego; + ego_entry->identifier = GNUNET_strdup (identifier); + GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); + return; + } + /* Ego renamed or added */ + if (identifier != NULL) { + for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) { + if (ego_entry->ego == ego) { + /* Rename */ + GNUNET_free (ego_entry->identifier); + ego_entry->identifier = GNUNET_strdup (identifier); + break; + } + } + if (NULL == ego_entry) { + /* Add */ + ego_entry = GNUNET_new (struct EgoEntry); + GNUNET_IDENTITY_ego_get_public_key (ego, &pk); + ego_entry->keystring = + GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); + ego_entry->ego = ego; + ego_entry->identifier = GNUNET_strdup (identifier); + GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); + } + } else { + /* Delete */ + for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) { + if (ego_entry->ego == ego) + break; + } + if (NULL != ego_entry) + GNUNET_CONTAINER_DLL_remove(handle->ego_head,handle->ego_tail, ego_entry); + } + +} + +static void +rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, + GNUNET_REST_ResultProcessor proc, + void *proc_cls) +{ + struct RequestHandle *handle = GNUNET_new (struct RequestHandle); + handle->oidc = GNUNET_new (struct OIDC_Variables); + if ( NULL == OIDC_identity_login_time ) + OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); + if ( NULL == OIDC_identity_grants ) + OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); + if ( NULL == OIDC_ticket_once ) + OIDC_ticket_once = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); + if ( NULL == OIDC_interpret_access_token ) + OIDC_interpret_access_token = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); + handle->response_code = 0; + handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; + handle->proc_cls = proc_cls; + handle->proc = proc; + handle->state = ID_REST_STATE_INIT; + handle->rest_handle = rest_handle; + + handle->url = GNUNET_strdup (rest_handle->url); + if (handle->url[strlen (handle->url)-1] == '/') + handle->url[strlen (handle->url)-1] = '\0'; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connecting...\n"); + handle->identity_handle = GNUNET_IDENTITY_connect (cfg, + &list_ego, + handle); + handle->gns_handle = GNUNET_GNS_connect (cfg); + handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg); + handle->timeout_task = + GNUNET_SCHEDULER_add_delayed (handle->timeout, + &do_timeout, + handle); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connected\n"); +} + +/** + * Entry point for the plugin. + * + * @param cls Config info + * @return NULL on error, otherwise the plugin context + */ +void * +libgnunet_plugin_rest_openid_connect_init (void *cls) +{ + static struct Plugin plugin; + struct GNUNET_REST_Plugin *api; + + cfg = cls; + if (NULL != plugin.cfg) + return NULL; /* can only initialize once! */ + memset (&plugin, 0, sizeof (struct Plugin)); + plugin.cfg = cfg; + api = GNUNET_new (struct GNUNET_REST_Plugin); + api->cls = &plugin; + api->name = GNUNET_REST_API_NS_OIDC; + api->process_request = &rest_identity_process_request; + GNUNET_asprintf (&allow_methods, + "%s, %s, %s, %s, %s", + MHD_HTTP_METHOD_GET, + MHD_HTTP_METHOD_POST, + MHD_HTTP_METHOD_PUT, + MHD_HTTP_METHOD_DELETE, + MHD_HTTP_METHOD_OPTIONS); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Identity Provider REST API initialized\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the plugin context (as returned by "init") + * @return always NULL + */ +void * +libgnunet_plugin_rest_openid_connect_done (void *cls) +{ + struct GNUNET_REST_Plugin *api = cls; + struct Plugin *plugin = api->cls; + plugin->cfg = NULL; + + struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it; + void *value = NULL; + hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create ( + OIDC_identity_login_time); + while (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) + { + if (NULL != value) + GNUNET_free(value); + } + GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time); + hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants); + while (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) + { + if (NULL != value) + GNUNET_free(value); + } + GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants); + hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_ticket_once); + while (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) + { + if (NULL != value) + GNUNET_free(value); + } + GNUNET_CONTAINER_multihashmap_destroy(OIDC_ticket_once); + hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_interpret_access_token); + while (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) + { + if (NULL != value) + GNUNET_free(value); + } + GNUNET_CONTAINER_multihashmap_destroy(OIDC_interpret_access_token); + GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it); + GNUNET_free_non_null (allow_methods); + GNUNET_free (api); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Identity Provider REST plugin is finished\n"); + return NULL; +} + +/* end of plugin_rest_identity_provider.c */ diff --git a/src/rest-plugins/plugin_rest_peerinfo.c b/src/rest-plugins/plugin_rest_peerinfo.c new file mode 100644 index 000000000..29b40088d --- /dev/null +++ b/src/rest-plugins/plugin_rest_peerinfo.c @@ -0,0 +1,820 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +/** + * @author Martin Schanzenbach + * @author Philippe Buschmann + * @file peerinfo/plugin_rest_peerinfo.c + * @brief GNUnet Peerinfo REST plugin + */ + +#include "platform.h" +#include "gnunet_rest_plugin.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_rest_lib.h" +#include "gnunet_json_lib.h" +#include "microhttpd.h" +#include + +/** + * Peerinfo Namespace + */ +#define GNUNET_REST_API_NS_PEERINFO "/peerinfo" + +/** + * Peerinfo parameter peer + */ +#define GNUNET_REST_PEERINFO_PEER "peer" + +/** + * Peerinfo parameter friend + */ +#define GNUNET_REST_PEERINFO_FRIEND "friend" + +/** + * Peerinfo parameter array + */ +#define GNUNET_REST_PEERINFO_ARRAY "array" + +/** + * Error message Unknown Error + */ +#define GNUNET_REST_PEERINFO_ERROR_UNKNOWN "Unknown Error" + +/** + * How long until we time out during address lookup? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) +/** + * The configuration handle + */ +const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * HTTP methods allows for this plugin + */ +static char* allow_methods; + +/** + * @brief struct returned by the initialization function of the plugin + */ +struct Plugin +{ + const struct GNUNET_CONFIGURATION_Handle *cfg; +}; + + +/** + * Record we keep for each printable address. + */ +struct AddressRecord +{ + /** + * Current address-to-string context (if active, otherwise NULL). + */ + struct GNUNET_TRANSPORT_AddressToStringContext *atsc; + + /** + * Address expiration time + */ + struct GNUNET_TIME_Absolute expiration; + + /** + * Printable address. + */ + char *result; + + /** + * Print context this address record belongs to. + */ + struct PrintContext *pc; +}; + + +/** + * Structure we use to collect printable address information. + */ +struct PrintContext +{ + /** + * Kept in DLL. + */ + struct PrintContext *next; + + /** + * Kept in DLL. + */ + struct PrintContext *prev; + + /** + * Identity of the peer. + */ + struct GNUNET_PeerIdentity peer; + + /** + * List of printable addresses. + */ + struct AddressRecord *address_list; + + /** + * Number of completed addresses in @e address_list. + */ + unsigned int num_addresses; + + /** + * Number of addresses allocated in @e address_list. + */ + unsigned int address_list_size; + + /** + * Current offset in @e address_list (counted down). + */ + unsigned int off; + + /** + * Hello was friend only, #GNUNET_YES or #GNUNET_NO + */ + int friend_only; + + /** + * RequestHandle + */ + struct RequestHandle *handle; + +}; + +/** + * Head of list of print contexts. + */ +static struct PrintContext *pc_head; + +/** + * Tail of list of print contexts. + */ +static struct PrintContext *pc_tail; + +/** + * The request handle + */ +struct RequestHandle +{ + /** + * JSON temporary array + */ + json_t *temp_array; + + /** + * Expiration time string + */ + char *expiration_str; + + /** + * Address string + */ + const char *address; + + /** + * Iteration peer public key + */ + char *pubkey; + + /** + * JSON response + */ + json_t *response; + + /** + * Handle to PEERINFO it + */ + struct GNUNET_PEERINFO_IteratorContext *list_it; + + /** + * Handle to PEERINFO + */ + struct GNUNET_PEERINFO_Handle *peerinfo_handle; + + /** + * Rest connection + */ + struct GNUNET_REST_RequestHandle *rest_handle; + + /** + * Desired timeout for the lookup (default is no timeout). + */ + struct GNUNET_TIME_Relative timeout; + + /** + * ID of a task associated with the resolution process. + */ + struct GNUNET_SCHEDULER_Task *timeout_task; + + /** + * The plugin result processor + */ + GNUNET_REST_ResultProcessor proc; + + /** + * The closure of the result processor + */ + void *proc_cls; + + /** + * The url + */ + char *url; + + /** + * Error response message + */ + char *emsg; + + /** + * Reponse code + */ + int response_code; + +}; + + +/** + * Cleanup lookup handle + * @param handle Handle to clean up + */ +static void +cleanup_handle (void *cls) +{ + struct RequestHandle *handle = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up\n"); + if (NULL != handle->timeout_task) + { + GNUNET_SCHEDULER_cancel (handle->timeout_task); + handle->timeout_task = NULL; + } + if (NULL != handle->url) + GNUNET_free (handle->url); + if (NULL != handle->emsg) + GNUNET_free (handle->emsg); + if (NULL != handle->address) + GNUNET_free ((char*)handle->address); + if (NULL != handle->expiration_str) + GNUNET_free (handle->expiration_str); + if (NULL != handle->pubkey) + GNUNET_free (handle->pubkey); + + if (NULL != handle->temp_array) + { + json_decref(handle->temp_array); + handle->temp_array = NULL; + } + if (NULL != handle->response) + { + json_decref(handle->response); + handle->response = NULL; + } + + if (NULL != handle->list_it) + { + GNUNET_PEERINFO_iterate_cancel(handle->list_it); + handle->list_it = NULL; + } + if (NULL != handle->peerinfo_handle) + { + GNUNET_PEERINFO_disconnect(handle->peerinfo_handle); + handle->peerinfo_handle = NULL; + } + + GNUNET_free (handle); +} + + +/** + * Task run on errors. Reports an error and cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_error (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + json_t *json_error = json_object(); + char *response; + + if (NULL == handle->emsg) + handle->emsg = GNUNET_strdup(GNUNET_REST_PEERINFO_ERROR_UNKNOWN); + + json_object_set_new(json_error,"error", json_string(handle->emsg)); + + if (0 == handle->response_code) + handle->response_code = MHD_HTTP_OK; + response = json_dumps (json_error, 0); + resp = GNUNET_REST_create_response (response); + handle->proc (handle->proc_cls, resp, handle->response_code); + json_decref(json_error); + GNUNET_free(response); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + +/** + * Function that assembles the response. + * + * @param cls the `struct RequestHandle` + */ +static void +peerinfo_list_finished (void *cls) +{ + struct RequestHandle *handle = cls; + char *result_str; + struct MHD_Response *resp; + + if (NULL == handle->response) + { + handle->response_code = MHD_HTTP_NOT_FOUND; + handle->emsg = GNUNET_strdup ("No peers found"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + result_str = json_dumps (handle->response, 0); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); + resp = GNUNET_REST_create_response (result_str); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free_non_null (result_str); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); +} + + +/** + * Iterator callback to go over all addresses and count them. + * + * @param cls `struct PrintContext *` with `off` to increment + * @param address the address + * @param expiration expiration time + * @return #GNUNET_OK to keep the address and continue + */ +static int +count_address (void *cls, + const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + struct PrintContext *pc = cls; + + if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us) + { + return GNUNET_OK; /* ignore expired address */ + } + + pc->off++; + return GNUNET_OK; +} + + +/** + * Print the collected address information to the console and free @a pc. + * + * @param pc printing context + */ +static void +dump_pc (struct PrintContext *pc) +{ + struct RequestHandle *handle; + unsigned int i; + json_t *response_entry; + json_t *temp_array; + json_t *object; + json_t *address; + json_t *expires; + json_t *friend_and_peer_json; + char *friend_and_peer; + + temp_array = json_array(); + response_entry = json_object(); + + for (i = 0; i < pc->num_addresses; i++) + { + if (NULL != pc->address_list[i].result) + { + object = json_object (); + address = json_string(pc->address_list[i].result); + expires = json_string( + GNUNET_STRINGS_absolute_time_to_string (pc->address_list[i].expiration)); + json_object_set (object, "address", address); + json_object_set (object, "expires", expires); + + json_decref(address); + json_decref(expires); + + json_array_append(temp_array, object); + json_decref(object); + GNUNET_free (pc->address_list[i].result); + } + } + + if (0 < json_array_size(temp_array)) + { + GNUNET_asprintf(&friend_and_peer, + "%s%s", + (GNUNET_YES == pc->friend_only) ? "F2F:" : "", + GNUNET_i2s_full (&pc->peer)); + friend_and_peer_json = json_string(friend_and_peer); + json_object_set(response_entry, + GNUNET_REST_PEERINFO_PEER, + friend_and_peer_json); + json_object_set(response_entry, + GNUNET_REST_PEERINFO_ARRAY, + temp_array); + json_array_append(pc->handle->response, response_entry); + json_decref(friend_and_peer_json); + GNUNET_free(friend_and_peer); + } + + json_decref (temp_array); + json_decref(response_entry); + + GNUNET_free_non_null (pc->address_list); + GNUNET_CONTAINER_DLL_remove (pc_head, + pc_tail, + pc); + handle = pc->handle; + GNUNET_free (pc); + + if ( (NULL == pc_head) && + (NULL == handle->list_it) ) + { + GNUNET_SCHEDULER_add_now (&peerinfo_list_finished, handle); + } + +} + + +/** + * Function to call with a human-readable format of an address + * + * @param cls closure + * @param address NULL on error, otherwise 0-terminated printable UTF-8 string + * @param res result of the address to string conversion: + * if #GNUNET_OK: address was valid (conversion to + * string might still have failed) + * if #GNUNET_SYSERR: address is invalid + */ +static void +process_resolved_address (void *cls, + const char *address, + int res) +{ + struct AddressRecord *ar = cls; + struct PrintContext *pc = ar->pc; + + if (NULL != address) + { + if (0 != strlen (address)) + { + if (NULL != ar->result) + GNUNET_free (ar->result); + ar->result = GNUNET_strdup (address); + } + return; + } + ar->atsc = NULL; + if (GNUNET_SYSERR == res) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Failure: Cannot convert address to string for peer `%s'\n"), + GNUNET_i2s (&ar->pc->peer)); + pc->num_addresses++; + if (pc->num_addresses == pc->address_list_size) + dump_pc (ar->pc); +} + + +/** + * Iterator callback to go over all addresses. + * + * @param cls closure + * @param address the address + * @param expiration expiration time + * @return #GNUNET_OK to keep the address and continue + */ +static int +print_address (void *cls, + const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + struct PrintContext *pc = cls; + struct AddressRecord *ar; + + if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us) + { + return GNUNET_OK; /* ignore expired address */ + } + + GNUNET_assert (0 < pc->off); + ar = &pc->address_list[--pc->off]; + ar->pc = pc; + ar->expiration = expiration; + GNUNET_asprintf (&ar->result, + "%s:%u:%u", + address->transport_name, + address->address_length, + address->local_info); + ar->atsc = GNUNET_TRANSPORT_address_to_string (cfg, + address, + GNUNET_NO, + TIMEOUT, + &process_resolved_address, + ar); + return GNUNET_OK; +} + + +/** + * Callback that processes each of the known HELLOs for the + * iteration response construction. + * + * @param cls closure, NULL + * @param peer id of the peer, NULL for last call + * @param hello hello message for the peer (can be NULL) + * @param err_msg message + */ +void +peerinfo_list_iteration(void *cls, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello, + const char *err_msg) +{ + struct RequestHandle *handle = cls; + struct PrintContext *pc; + int friend_only; + + if (NULL == handle->response) + { + handle->response = json_array(); + } + + if (NULL == peer) + { + handle->list_it = NULL; + handle->emsg = GNUNET_strdup ("Error in communication with peerinfo"); + if (NULL != err_msg) + { + GNUNET_free(handle->emsg); + handle->emsg = GNUNET_strdup (err_msg); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + } + if (NULL == pc_head) + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (NULL == hello) + return; + + friend_only = GNUNET_NO; + if (NULL != hello) + friend_only = GNUNET_HELLO_is_friend_only (hello); + + pc = GNUNET_new(struct PrintContext); + GNUNET_CONTAINER_DLL_insert (pc_head, + pc_tail, + pc); + pc->peer = *peer; + pc->friend_only = friend_only; + pc->handle = handle; + GNUNET_HELLO_iterate_addresses (hello, + GNUNET_NO, + &count_address, + pc); + if (0 == pc->off) + { + dump_pc (pc); + return; + } + pc->address_list_size = pc->off; + pc->address_list = GNUNET_malloc( + sizeof(struct AddressRecord) * pc->off); + GNUNET_HELLO_iterate_addresses (hello, + GNUNET_NO, + &print_address, + pc); +} + +/** + * Handle peerinfo GET request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +void +peerinfo_get (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct GNUNET_HashCode key; + const struct GNUNET_PeerIdentity *specific_peer; + //GNUNET_PEER_Id peer_id; + int include_friend_only; + char* include_friend_only_str; + + include_friend_only = GNUNET_NO; + GNUNET_CRYPTO_hash (GNUNET_REST_PEERINFO_FRIEND, + strlen (GNUNET_REST_PEERINFO_FRIEND), + &key); + if ( GNUNET_YES + == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, + &key)) + { + include_friend_only_str = GNUNET_CONTAINER_multihashmap_get ( + con_handle->url_param_map, &key); + if (0 == strcmp(include_friend_only_str, "yes")) + { + include_friend_only = GNUNET_YES; + } + } + + specific_peer = NULL; + GNUNET_CRYPTO_hash (GNUNET_REST_PEERINFO_PEER, + strlen (GNUNET_REST_PEERINFO_PEER), + &key); + if ( GNUNET_YES + == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, + &key)) + { + //peer_id = *(unsigned int*)GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key); + //specific_peer = GNUNET_PEER_resolve2(peer_id); + } + + handle->list_it = GNUNET_PEERINFO_iterate(handle->peerinfo_handle, + include_friend_only, + specific_peer, + &peerinfo_list_iteration, + handle); +} + + + +/** + * Respond to OPTIONS request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +options_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct MHD_Response *resp; + struct RequestHandle *handle = cls; + + //independent of path return all options + resp = GNUNET_REST_create_response (NULL); + MHD_add_response_header (resp, + "Access-Control-Allow-Methods", + allow_methods); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); + return; +} + + +/** + * Handle rest request + * + * @param handle the request handle + */ +static void +init_cont (struct RequestHandle *handle) +{ + struct GNUNET_REST_RequestHandlerError err; + static const struct GNUNET_REST_RequestHandler handlers[] = { + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_PEERINFO, &peerinfo_get}, + {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_PEERINFO, &options_cont}, + GNUNET_REST_HANDLER_END + }; + + if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, + handlers, + &err, + handle)) + { + handle->response_code = err.error_code; + GNUNET_SCHEDULER_add_now (&do_error, handle); + } +} + + +/** + * Function processing the REST call + * + * @param method HTTP method + * @param url URL of the HTTP request + * @param data body of the HTTP request (optional) + * @param data_size length of the body + * @param proc callback function for the result + * @param proc_cls closure for callback function + * @return GNUNET_OK if request accepted + */ +static void +rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle, + GNUNET_REST_ResultProcessor proc, + void *proc_cls) +{ + struct RequestHandle *handle = GNUNET_new (struct RequestHandle); + + handle->response_code = 0; + handle->timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60); + handle->proc_cls = proc_cls; + handle->proc = proc; + handle->rest_handle = rest_handle; + + handle->url = GNUNET_strdup (rest_handle->url); + if (handle->url[strlen (handle->url)-1] == '/') + handle->url[strlen (handle->url)-1] = '\0'; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); + handle->peerinfo_handle = GNUNET_PEERINFO_connect(cfg); + init_cont(handle); + handle->timeout_task = + GNUNET_SCHEDULER_add_delayed (handle->timeout, + &do_error, + handle); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); +} + + +/** + * Entry point for the plugin. + * + * @param cls Config info + * @return NULL on error, otherwise the plugin context + */ +void * +libgnunet_plugin_rest_peerinfo_init (void *cls) +{ + static struct Plugin plugin; + struct GNUNET_REST_Plugin *api; + + cfg = cls; + if (NULL != plugin.cfg) + return NULL; /* can only initialize once! */ + memset (&plugin, 0, sizeof (struct Plugin)); + plugin.cfg = cfg; + api = GNUNET_new (struct GNUNET_REST_Plugin); + api->cls = &plugin; + api->name = GNUNET_REST_API_NS_PEERINFO; + api->process_request = &rest_process_request; + GNUNET_asprintf (&allow_methods, + "%s, %s, %s, %s, %s", + MHD_HTTP_METHOD_GET, + MHD_HTTP_METHOD_POST, + MHD_HTTP_METHOD_PUT, + MHD_HTTP_METHOD_DELETE, + MHD_HTTP_METHOD_OPTIONS); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Peerinfo REST API initialized\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the plugin context (as returned by "init") + * @return always NULL + */ +void * +libgnunet_plugin_rest_peerinfo_done (void *cls) +{ + struct GNUNET_REST_Plugin *api = cls; + struct Plugin *plugin = api->cls; + plugin->cfg = NULL; + + GNUNET_free_non_null (allow_methods); + GNUNET_free (api); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peerinfo REST plugin is finished\n"); + return NULL; +} + +/* end of plugin_rest_peerinfo.c */ + diff --git a/src/rest/Makefile.am b/src/rest/Makefile.am index f87335152..6c23ad2a6 100644 --- a/src/rest/Makefile.am +++ b/src/rest/Makefile.am @@ -10,7 +10,6 @@ libexecdir= $(pkglibdir)/libexec/ pkgcfg_DATA = \ rest.conf - if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif @@ -29,18 +28,6 @@ libexec_PROGRAMS = \ EXTRA_DIST = \ rest.conf -plugin_LTLIBRARIES = libgnunet_plugin_rest_copying.la - -libgnunet_plugin_rest_copying_la_SOURCES = \ - plugin_rest_copying.c -libgnunet_plugin_rest_copying_la_LIBADD = \ - libgnunetrest.la \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -lmicrohttpd -libgnunet_plugin_rest_copying_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - - gnunet_rest_server_SOURCES = \ gnunet-rest-server.c diff --git a/src/rest/plugin_rest_copying.c b/src/rest/plugin_rest_copying.c deleted file mode 100644 index 668dc5d38..000000000 --- a/src/rest/plugin_rest_copying.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2018 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -/** - * @author Martin Schanzenbach - * @file gns/plugin_rest_copying.c - * @brief REST plugin that serves licensing information. - * - */ - -#include "platform.h" -#include "gnunet_rest_plugin.h" -#include - -#define GNUNET_REST_API_NS_COPYING "/copying" - -#define GNUNET_REST_COPYING_TEXT "GNU Affero General Public License version 3 or later. See also: " - -/** - * @brief struct returned by the initialization function of the plugin - */ -struct Plugin -{ - const struct GNUNET_CONFIGURATION_Handle *cfg; -}; - -const struct GNUNET_CONFIGURATION_Handle *cfg; - -struct RequestHandle -{ - /** - * Handle to rest request - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * HTTP response code - */ - int response_code; - -}; - - -/** - * Cleanup request handle. - * - * @param handle Handle to clean up - */ -static void -cleanup_handle (struct RequestHandle *handle) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Cleaning up\n"); - GNUNET_free (handle); -} - - -/** - * Task run on shutdown. Cleans up everything. - * - * @param cls unused - * @param tc scheduler context - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, handle->response_code); - cleanup_handle (handle); -} - - -/** - * Handle rest request - * - * @param handle the lookup handle - */ -static void -get_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - resp = GNUNET_REST_create_response (GNUNET_REST_COPYING_TEXT); - handle->proc (handle->proc_cls, - resp, - MHD_HTTP_OK); - cleanup_handle (handle); -} - - - -/** - * Handle rest request - * - * @param handle the lookup handle - */ -static void -options_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - resp = GNUNET_REST_create_response (NULL); - MHD_add_response_header (resp, - "Access-Control-Allow-Methods", - MHD_HTTP_METHOD_GET); - handle->proc (handle->proc_cls, - resp, - MHD_HTTP_OK); - cleanup_handle (handle); -} - - -/** - * Function processing the REST call - * - * @param method HTTP method - * @param url URL of the HTTP request - * @param data body of the HTTP request (optional) - * @param data_size length of the body - * @param proc callback function for the result - * @param proc_cls closure for @a proc - * @return #GNUNET_OK if request accepted - */ -static void -rest_copying_process_request (struct GNUNET_REST_RequestHandle *conndata_handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) -{ - static const struct GNUNET_REST_RequestHandler handlers[] = { - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_COPYING, &get_cont}, - {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_COPYING, &options_cont}, - GNUNET_REST_HANDLER_END - }; - struct RequestHandle *handle = GNUNET_new (struct RequestHandle); - struct GNUNET_REST_RequestHandlerError err; - - handle->proc_cls = proc_cls; - handle->proc = proc; - handle->rest_handle = conndata_handle; - - if (GNUNET_NO == GNUNET_REST_handle_request (conndata_handle, - handlers, - &err, - handle)) - { - handle->response_code = err.error_code; - GNUNET_SCHEDULER_add_now (&do_error, handle); - } -} - - -/** - * Entry point for the plugin. - * - * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*" - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_rest_copying_init (void *cls) -{ - static struct Plugin plugin; - cfg = cls; - struct GNUNET_REST_Plugin *api; - - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof (struct Plugin)); - plugin.cfg = cfg; - api = GNUNET_new (struct GNUNET_REST_Plugin); - api->cls = &plugin; - api->name = GNUNET_REST_API_NS_COPYING; - api->process_request = &rest_copying_process_request; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("COPYING REST API initialized\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ -void * -libgnunet_plugin_rest_copying_done (void *cls) -{ - struct GNUNET_REST_Plugin *api = cls; - struct Plugin *plugin = api->cls; - - plugin->cfg = NULL; - GNUNET_free (api); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "COPYING REST plugin is finished\n"); - return NULL; -} - -/* end of plugin_rest_copying.c */ -- cgit v1.2.3 From e4e62ee393f90cd9b788211f6d311cb180e38b30 Mon Sep 17 00:00:00 2001 From: "Schanzenbach, Martin" Date: Mon, 13 Aug 2018 09:56:48 +0200 Subject: fix dep handling rest plugin --- po/POTFILES.in | 4 ++-- src/jsonapi/Makefile.am | 7 +++++-- src/rest-plugins/Makefile.am | 6 ++++-- 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/po/POTFILES.in b/po/POTFILES.in index a1cdac7f2..1f2753b9b 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -211,7 +211,6 @@ src/jsonapi/jsonapi_document.c src/jsonapi/jsonapi_error.c src/jsonapi/jsonapi_relationship.c src/jsonapi/jsonapi_resource.c -src/jsonapi/plugin_rest_openid_connect.c src/jsonapi/plugin_rest_reclaim.c src/multicast/gnunet-multicast.c src/multicast/gnunet-service-multicast.c @@ -292,7 +291,6 @@ src/reclaim-attribute/reclaim_attribute.c src/reclaim/gnunet-reclaim.c src/reclaim/gnunet-service-reclaim.c src/reclaim/jwt.c -src/reclaim/oidc_helper.c src/reclaim/plugin_gnsrecord_reclaim.c src/reclaim/plugin_reclaim_sqlite.c src/reclaim/reclaim_api.c @@ -310,10 +308,12 @@ src/regex/regex_internal_dht.c src/regex/regex_test_graph.c src/regex/regex_test_lib.c src/regex/regex_test_random.c +src/rest-plugins/oidc_helper.c src/rest-plugins/plugin_rest_copying.c src/rest-plugins/plugin_rest_gns.c src/rest-plugins/plugin_rest_identity.c src/rest-plugins/plugin_rest_namestore.c +src/rest-plugins/plugin_rest_openid_connect.c src/rest-plugins/plugin_rest_peerinfo.c src/rest/gnunet-rest-server.c src/rest/rest.c diff --git a/src/jsonapi/Makefile.am b/src/jsonapi/Makefile.am index 0c6d60b10..489c4d9f2 100644 --- a/src/jsonapi/Makefile.am +++ b/src/jsonapi/Makefile.am @@ -8,8 +8,11 @@ endif lib_LTLIBRARIES = \ libgnunetjsonapi.la \ - libgnunetjsonapiutils.la \ - libgnunet_plugin_rest_reclaim.la + libgnunetjsonapiutils.la + +if HAVE_ABE +lib_LTLIBRARIES += libgnunet_plugin_rest_reclaim.la +endif libgnunet_plugin_rest_reclaim_la_SOURCES = \ plugin_rest_reclaim.c diff --git a/src/rest-plugins/Makefile.am b/src/rest-plugins/Makefile.am index ae74dc78a..3acf8839e 100644 --- a/src/rest-plugins/Makefile.am +++ b/src/rest-plugins/Makefile.am @@ -22,8 +22,10 @@ plugin_LTLIBRARIES = \ libgnunet_plugin_rest_peerinfo.la \ libgnunet_plugin_rest_identity.la \ libgnunet_plugin_rest_namestore.la \ - libgnunet_plugin_rest_gns.la \ - libgnunet_plugin_rest_openid_connect.la + libgnunet_plugin_rest_gns.la +if HAVE_ABE +plugin_LTLIBRARIES += libgnunet_plugin_rest_openid_connect.la +endif libgnunet_plugin_rest_copying_la_SOURCES = \ -- cgit v1.2.3 From 341c1dd692c62a88eeff34fca155ce2377677d4b Mon Sep 17 00:00:00 2001 From: Phil Date: Mon, 13 Aug 2018 11:23:13 +0200 Subject: moved test files and fixed namestore --- src/gns/test_plugin_rest_gns.sh | 50 ------- src/identity/test_plugin_rest_identity.sh | 157 -------------------- src/namestore/test_plugin_rest_namestore.sh | 147 ------------------- src/rest-plugins/plugin_rest_namestore.c | 193 +++++++++++++++++++------ src/rest-plugins/test_plugin_rest_gns.sh | 50 +++++++ src/rest-plugins/test_plugin_rest_identity.sh | 157 ++++++++++++++++++++ src/rest-plugins/test_plugin_rest_namestore.sh | 147 +++++++++++++++++++ 7 files changed, 500 insertions(+), 401 deletions(-) delete mode 100755 src/gns/test_plugin_rest_gns.sh delete mode 100755 src/identity/test_plugin_rest_identity.sh delete mode 100755 src/namestore/test_plugin_rest_namestore.sh create mode 100755 src/rest-plugins/test_plugin_rest_gns.sh create mode 100755 src/rest-plugins/test_plugin_rest_identity.sh create mode 100755 src/rest-plugins/test_plugin_rest_namestore.sh (limited to 'src') diff --git a/src/gns/test_plugin_rest_gns.sh b/src/gns/test_plugin_rest_gns.sh deleted file mode 100755 index ec495a04b..000000000 --- a/src/gns/test_plugin_rest_gns.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/bash - -#First, start gnunet-arm and the rest-service. -#Exit 0 means success, exit 1 means failed test - -gns_link="http://localhost:7776/gns" -wrong_link="http://localhost:7776/gnsandmore" - -curl_get () { - #$1 is link - #$2 is grep - cache="$(curl -v "$1" 2>&1 | grep "$2")" - #echo $cache - if [ "" == "$cache" ] - then - exit 1 - fi -} - -gnunet-identity -D "test_plugin_rest_gns" > /dev/null 2>&1 - -curl_get "$gns_link/www.test_plugin_rest_gns" "error" - -gnunet-identity -C "test_plugin_rest_gns" - -curl_get "$gns_link/www.test_plugin_rest_gns" "\[\]" - -gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1.1.1.1 -t A - -curl_get "$gns_link/www.test_plugin_rest_gns" "1.1.1.1" - -gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1::1 -t AAAA - -curl_get "$gns_link/www.test_plugin_rest_gns" "1::1.*1.1.1.1" - -gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1.1.1.2 -t A - -curl_get "$gns_link/www.test_plugin_rest_gns" "1.1.1.2.*1::1.*1.1.1.1" -curl_get "$gns_link/www.test_plugin_rest_gns?record_type=A" "1.1.1.2.*1.1.1.1" -curl_get "$gns_link/www.test_plugin_rest_gns?record_type=AAAA" "1::1" -curl_get "$gns_link/www.test_plugin_rest_gns?record_type=WRONG_TYPE" "1.1.1.2.*1::1.*1.1.1.1" - -gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www1 -e 1d -V 1.1.1.1 -t A -curl_get "$gns_link/www1.test_plugin_rest_gns" "1.1.1.1" - -gnunet-identity -D "test_plugin_rest_gns" > /dev/null 2>&1 - -curl_get "$gns_link/www1.test_plugin_rest_gns" "error" - -exit 0 diff --git a/src/identity/test_plugin_rest_identity.sh b/src/identity/test_plugin_rest_identity.sh deleted file mode 100755 index a5879dd7e..000000000 --- a/src/identity/test_plugin_rest_identity.sh +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/bash - -#First, start gnunet-arm and the rest-service. -#Exit 0 means success, exit 1 means failed test - -identity_link="http://localhost:7776/identity" -wrong_link="http://localhost:7776/identityandmore" - - -curl_get () { - #$1 is link - #$2 is grep - cache="$(curl -v "$1" 2>&1 | grep "$2")" - #echo $cache - if [ "" == "$cache" ] - then - exit 1 - fi -} - -curl_post () { - #$1 is link - #$2 is data - #$3 is grep - cache="$(curl -v -X "POST" "$1" --data "$2" 2>&1 | grep "$3")" - #echo $cache - if [ "" == "$cache" ] - then - exit 1 - fi -} - -curl_delete () { - #$1 is link - #$2 is grep - cache="$(curl -v -X "DELETE" "$1" 2>&1 | grep "$2")" - #echo $cache - if [ "" == "$cache" ] - then - exit 1 - fi -} - -curl_put () { - #$1 is link - #$2 is data - #$3 is grep - cache="$(curl -v -X "PUT" "$1" --data "$2" 2>&1 | grep "$3")" - #echo $cache - if [ "" == "$cache" ] - then - exit 1 - fi -} - -#Test GET -test="$(gnunet-identity -d)" -#if no identity exists -if [ "" == "$test" ] -then - curl_get "$identity_link/all" "error" - gnunet-identity -C "test_plugin_rest_identity" - name="$(gnunet-identity -d | awk 'NR==1{print $1}')" - public="$(gnunet-identity -d | awk 'NR==1{print $3}')" - - curl_get "${identity_link}/name/$name" "$public" - curl_get "${identity_link}/name/$public" "error" - curl_get "${identity_link}/name/" "error" - - curl_get "${identity_link}/pubkey/$public" "$name" - curl_get "${identity_link}/pubkey/$name" "error" - curl_get "${identity_link}/pubkey/" "error" - - gnunet-identity -D "test_plugin_rest_identity" -else - name="$(gnunet-identity -d | awk 'NR==1{print $1}')" - public="$(gnunet-identity -d | awk 'NR==1{print $3}')" - - curl_get "${identity_link}/name/$name" "$public" - curl_get "${identity_link}/name/$public" "error" - curl_get "${identity_link}/name/" "error" - - curl_get "${identity_link}/pubkey/$public" "$name" - curl_get "${identity_link}/pubkey/$name" "error" - curl_get "${identity_link}/pubkey/" "error" -fi - -#Test POST -gnunet-identity -D "test_plugin_rest_identity" > /dev/null 2>&1 -gnunet-identity -D "test_plugin_rest_identity1" > /dev/null 2>&1 - -curl_post "${identity_link}" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 201 Created" -curl_post "${identity_link}" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 409" -curl_post "${identity_link}" '{"name":"Test_plugin_rest_identity"}' "HTTP/1.1 409" -curl_post "${identity_link}" '{}' "error" -curl_post "${identity_link}" '' "error" -curl_post "${identity_link}" '{"name":""}' "error" -curl_post "${identity_link}" '{"name":123}' "error" -curl_post "${identity_link}" '{"name":[]}' "error" -curl_post "${identity_link}" '{"name1":"test_plugin_rest_identity"}' "error" -curl_post "${identity_link}" '{"other":""}' "error" -curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1", "other":"test_plugin_rest_identity2"}' "error" - -#Test PUT -name="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $1}')" -public="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $3}')" - -curl_put "${identity_link}/pubkey/$public" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 204" -curl_put "${identity_link}/pubkey/$public" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 409" -curl_put "${identity_link}/pubkey/${public}xx" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404" -curl_put "${identity_link}/pubkey/" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404" -curl_put "${identity_link}/pubke" '{"newname":"test_plugin_rest_identity1"}' "error" -curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","other":"sdfdsf"}' "error" -curl_put "${identity_link}/pubkey/$name" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404" -curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"test_plugin_rest_identity"}' "HTTP/1.1 204" -curl_put "${identity_link}/pubkey/$public" '{"newnam":"test_plugin_rest_identity"}' "error" -curl_put "${identity_link}/name/test_plugin_rest_identity" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 204" -curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"TEST_plugin_rest_identity1"}' "HTTP/1.1 409" -curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 409" -curl_put "${identity_link}/name/test_plugin_rest_identityxxx" '{"newname":"test_plugin_rest_identity"}' "HTTP/1.1 404" -curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"test_plugin_rest_identity"}' "HTTP/1.1 204" -curl_put "${identity_link}/name/test_plugin_rest_identity" '{"newnam":"test_plugin_rest_identityfail"}' "error" - -#Test subsystem -curl_put "${identity_link}/subsystem/test_plugin_rest_identity" '{"subsystem":"namestore"}' "HTTP/1.1 204" -curl_put "${identity_link}/subsystem/test_plugin_rest_identity" '{"subsystem":"namestore"}' "HTTP/1.1 204" -curl_get "${identity_link}/subsystem/namestore" "test_plugin_rest_identity" -public="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $3}')" -curl_put "${identity_link}/subsystem/$public" '{"subsystem":"namestore"}' "HTTP/1.1 404" -curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created" -curl_get "${identity_link}/subsystem/test_plugin_rest_identity_no_subsystem" "error" -curl_put "${identity_link}/subsystem/test_plugin_rest_identity1" '{"subsystem":"test_plugin_rest_identity_no_subsystem"}' "HTTP/1.1 204" -curl_get "${identity_link}/subsystem/test_plugin_rest_identity_no_subsystem" "test_plugin_rest_identity1" - -curl_put "${identity_link}/subsystem/test_plugin_rest_identity1" '{"subsyste":"test_plugin_rest_identity_no_subsystem"}' "error" -curl_put "${identity_link}/subsystem/test_plugin_rest_identity1" '{"subsystem":"test_plugin_rest_identity_no_subsystem"}' "HTTP/1.1 204" - -#Test DELETE -curl_delete "${identity_link}/name/test_plugin_rest_identity" "HTTP/1.1 204" -curl_get "${identity_link}/name/test_plugin_rest_identity" "error" -curl_delete "${identity_link}/name/TEST_plugin_rest_identity1" "HTTP/1.1 204" -curl_delete "${identity_link}/name/test_plugin_rest_identity1" "HTTP/1.1 404" -curl_get "${identity_link}/name/test_plugin_rest_identity1" "error" -curl_delete "${identity_link}/name/test_plugin_rest_identity_not_found" "HTTP/1.1 404" -curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created" -public="$(gnunet-identity -d | grep "test_plugin_rest_identity1" | awk 'NR==1{print $3}')" -curl_delete "${identity_link}/pubkey/$public" "HTTP/1.1 204" -curl_delete "${identity_link}/pubke/$public" "error" -curl_delete "${identity_link}/pubkey/${public}other=232" "HTTP/1.1 404" - -#Test wrong_link -curl_get "$wrong_link" "HTTP/1.1 404" -curl_post "$wrong_link" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 404" -curl_put "$wrong_link/name/test_plugin_rest_identity" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404" -curl_delete "$wrong_link/name/test_plugin_rest_identity1" "HTTP/1.1 404" - -exit 0; diff --git a/src/namestore/test_plugin_rest_namestore.sh b/src/namestore/test_plugin_rest_namestore.sh deleted file mode 100755 index 532c7caae..000000000 --- a/src/namestore/test_plugin_rest_namestore.sh +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/bash - -#First, start gnunet-arm and the rest-service. -#Exit 0 means success, exit 1 means failed test - -namestore_link="http://localhost:7776/namestore" -wrong_link="http://localhost:7776/namestoreandmore" - - -curl_get () { - #$1 is link - #$2 is grep - cache="$(curl -v "$1" 2>&1 | grep "$2")" - echo $cache - if [ "" == "$cache" ] - then - exit 1 - fi -} - -curl_post () { - #$1 is link - #$2 is data - #$3 is grep - cache="$(curl -v -X "POST" "$1" --data "$2" 2>&1 | grep "$3")" - echo $cache - if [ "" == "$cache" ] - then - exit 1 - fi -} - -curl_delete () { - #$1 is link - #$2 is grep - cache="$(curl -v -X "DELETE" "$1" 2>&1 | grep "$2")" - echo $cache - if [ "" == "$cache" ] - then - exit 1 - fi -} - -# curl_put () { -# #$1 is link -# #$2 is data -# #$3 is grep -# cache="$(curl -v -X "PUT" "$1" --data "$2" 2>&1 | grep "$3")" -# #echo $cache -# if [ "" == "$cache" ] -# then -# exit 1 -# fi -# } - -#Test subsystem default identity - -#Test GET -gnunet-identity -D "test_plugin_rest_namestore" -gnunet-identity -C "test_plugin_rest_namestore" -test="$(gnunet-namestore -D -z "test_plugin_rest_namestore")" -name="test_plugin_rest_namestore" -public="$(gnunet-identity -d | grep "test_plugin_rest_namestore" | awk 'NR==1{print $3}')" -if [ "" == "$test" ] -then - #if no entries for test_plugin_rest_namestore - curl_get "${namestore_link}/$name" "error" - curl_get "${namestore_link}/" "error" - curl_get "${namestore_link}/$public" "error" -else - #if entries exists (that should not be possible) - curl_get "${namestore_link}" "HTTP/1.1 200 OK" - curl_get "${namestore_link}/$name" "HTTP/1.1 200 OK" - curl_get "${namestore_link}/" "error" - curl_get "${namestore_link}/$public" "error" -fi -gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" -curl_get "${namestore_link}" "HTTP/1.1 200 OK" -curl_get "${namestore_link}/$name" "HTTP/1.1 200 OK" -curl_get "${namestore_link}/" "error" -curl_get "${namestore_link}/$public" "error" -gnunet-namestore -z $name -d -n "test_entry" - -#Test POST with NAME -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -#value -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value_missing":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -#time -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"0d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"10000d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"now","flag":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"","flag":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time_missing":"1d","flag":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -#flag -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":2,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":8,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":16,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":-1,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":"Test","record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag_missing":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -#record_name -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":""}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name_missing":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 - -#wrong zone -curl_post "${namestore_link}/$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 - -#Test DELETE -gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" -curl_delete "${namestore_link}/$name?record_name=test_entry" "HTTP/1.1 204" -curl_delete "${namestore_link}/$name?record_name=test_entry" "error" -gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" -curl_delete "${namestore_link}/$public?record_name=test_entry" "error" - - -#Test default identity -#not possible without defining - -exit 0; - diff --git a/src/rest-plugins/plugin_rest_namestore.c b/src/rest-plugins/plugin_rest_namestore.c index 1d72d13ff..2926f4b90 100644 --- a/src/rest-plugins/plugin_rest_namestore.c +++ b/src/rest-plugins/plugin_rest_namestore.c @@ -458,10 +458,7 @@ namestore_list_finished (void *cls) handle->list_it = NULL; if (NULL == handle->resp_object) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } + handle->resp_object = json_array(); result_str = json_dumps (handle->resp_object, 0); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); @@ -508,6 +505,48 @@ namestore_list_iteration (void *cls, GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1); } +/** + * @param cls closure + * @param ego ego handle + * @param ctx context for application to store data for this ego + * (during the lifetime of this process, initially NULL) + * @param identifier identifier assigned by the user for this ego, + * NULL if the user just deleted the ego and it + * must thus no longer be used + */ +static void +default_ego_get (void *cls, + struct GNUNET_IDENTITY_Ego *ego, + void **ctx, + const char *identifier) +{ + struct RequestHandle *handle = cls; + handle->op = NULL; + + if (ego == NULL) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego); + + handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle, + handle->zone_pkey, + &namestore_iteration_error, + handle, + &namestore_list_iteration, + handle, + &namestore_list_finished, + handle); + if (NULL == handle->list_it) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } +} + /** * Handle namestore GET request @@ -546,10 +585,13 @@ namestore_get (struct GNUNET_REST_RequestHandle *con_handle, { handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego); } + if (NULL == handle->zone_pkey) { - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE); - GNUNET_SCHEDULER_add_now (&do_error, handle); + handle->op = GNUNET_IDENTITY_get (handle->identity_handle, + "namestore", + &default_ego_get, + handle); return; } handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle, @@ -569,6 +611,48 @@ namestore_get (struct GNUNET_REST_RequestHandle *con_handle, } +/** + * @param cls closure + * @param ego ego handle + * @param ctx context for application to store data for this ego + * (during the lifetime of this process, initially NULL) + * @param identifier identifier assigned by the user for this ego, + * NULL if the user just deleted the ego and it + * must thus no longer be used + */ +static void +default_ego_post (void *cls, + struct GNUNET_IDENTITY_Ego *ego, + void **ctx, + const char *identifier) +{ + struct RequestHandle *handle = cls; + handle->op = NULL; + + if (ego == NULL) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego); + + handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle, + handle->zone_pkey, + handle->record_name, + 1, + handle->rd, + &create_finished, + handle); + if (NULL == handle->add_qe) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } +} + + /** * Handle namestore POST request * @@ -662,18 +746,62 @@ namestore_add (struct GNUNET_REST_RequestHandle *con_handle, handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego); } if (NULL == handle->zone_pkey) + { + handle->op = GNUNET_IDENTITY_get (handle->identity_handle, + "namestore", + &default_ego_post, + handle); + return; + } + handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle, + handle->zone_pkey, + handle->record_name, + 1, + handle->rd, + &create_finished, + handle); + if (NULL == handle->add_qe) + { + handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } +} + + +/** + * @param cls closure + * @param ego ego handle + * @param ctx context for application to store data for this ego + * (during the lifetime of this process, initially NULL) + * @param identifier identifier assigned by the user for this ego, + * NULL if the user just deleted the ego and it + * must thus no longer be used + */ +static void +default_ego_delete (void *cls, + struct GNUNET_IDENTITY_Ego *ego, + void **ctx, + const char *identifier) +{ + struct RequestHandle *handle = cls; + handle->op = NULL; + + if (ego == NULL) { handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } + handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego); + handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle, - handle->zone_pkey, - handle->record_name, - 1, - handle->rd, - &create_finished, - handle); + handle->zone_pkey, + handle->record_name, + 0, + NULL, + &del_finished, + handle); if (NULL == handle->add_qe) { handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED); @@ -736,8 +864,10 @@ namestore_delete (struct GNUNET_REST_RequestHandle *con_handle, if (NULL == handle->zone_pkey) { - handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE); - GNUNET_SCHEDULER_add_now (&do_error, handle); + handle->op = GNUNET_IDENTITY_get (handle->identity_handle, + "namestore", + &default_ego_delete, + handle); return; } @@ -811,30 +941,6 @@ init_cont (struct RequestHandle *handle) } } -/** - * @param cls closure - * @param ego ego handle - * @param ctx context for application to store data for this ego - * (during the lifetime of this process, initially NULL) - * @param identifier identifier assigned by the user for this ego, - * NULL if the user just deleted the ego and it - * must thus no longer be used - */ -static void -default_ego_cb (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *identifier) -{ - struct RequestHandle *handle = cls; - handle->op = NULL; - - if (ego != NULL) - { - handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego); - } -} - /** * This function is initially called for all egos and then again @@ -877,17 +983,10 @@ id_connect_cb (void *cls, struct EgoEntry *ego_entry; struct GNUNET_CRYPTO_EcdsaPublicKey pk; - if ((NULL == ego) && (NULL == handle->zone_pkey)) - { - handle->op = GNUNET_IDENTITY_get (handle->identity_handle, - "namestore", - &default_ego_cb, - handle); - } if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state)) { handle->state = ID_REST_STATE_POST_INIT; - init_cont (handle); + init_cont(handle); return; } if (ID_REST_STATE_INIT == handle->state) @@ -934,8 +1033,8 @@ rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle, handle->url[strlen (handle->url)-1] = '\0'; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); - handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &id_connect_cb, handle); handle->ns_handle = GNUNET_NAMESTORE_connect (cfg); + handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &id_connect_cb, handle); handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_error, diff --git a/src/rest-plugins/test_plugin_rest_gns.sh b/src/rest-plugins/test_plugin_rest_gns.sh new file mode 100755 index 000000000..ec495a04b --- /dev/null +++ b/src/rest-plugins/test_plugin_rest_gns.sh @@ -0,0 +1,50 @@ +#!/usr/bin/bash + +#First, start gnunet-arm and the rest-service. +#Exit 0 means success, exit 1 means failed test + +gns_link="http://localhost:7776/gns" +wrong_link="http://localhost:7776/gnsandmore" + +curl_get () { + #$1 is link + #$2 is grep + cache="$(curl -v "$1" 2>&1 | grep "$2")" + #echo $cache + if [ "" == "$cache" ] + then + exit 1 + fi +} + +gnunet-identity -D "test_plugin_rest_gns" > /dev/null 2>&1 + +curl_get "$gns_link/www.test_plugin_rest_gns" "error" + +gnunet-identity -C "test_plugin_rest_gns" + +curl_get "$gns_link/www.test_plugin_rest_gns" "\[\]" + +gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1.1.1.1 -t A + +curl_get "$gns_link/www.test_plugin_rest_gns" "1.1.1.1" + +gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1::1 -t AAAA + +curl_get "$gns_link/www.test_plugin_rest_gns" "1::1.*1.1.1.1" + +gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1.1.1.2 -t A + +curl_get "$gns_link/www.test_plugin_rest_gns" "1.1.1.2.*1::1.*1.1.1.1" +curl_get "$gns_link/www.test_plugin_rest_gns?record_type=A" "1.1.1.2.*1.1.1.1" +curl_get "$gns_link/www.test_plugin_rest_gns?record_type=AAAA" "1::1" +curl_get "$gns_link/www.test_plugin_rest_gns?record_type=WRONG_TYPE" "1.1.1.2.*1::1.*1.1.1.1" + +gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www1 -e 1d -V 1.1.1.1 -t A +curl_get "$gns_link/www1.test_plugin_rest_gns" "1.1.1.1" + +gnunet-identity -D "test_plugin_rest_gns" > /dev/null 2>&1 + +curl_get "$gns_link/www1.test_plugin_rest_gns" "error" + +exit 0 diff --git a/src/rest-plugins/test_plugin_rest_identity.sh b/src/rest-plugins/test_plugin_rest_identity.sh new file mode 100755 index 000000000..a5879dd7e --- /dev/null +++ b/src/rest-plugins/test_plugin_rest_identity.sh @@ -0,0 +1,157 @@ +#!/usr/bin/bash + +#First, start gnunet-arm and the rest-service. +#Exit 0 means success, exit 1 means failed test + +identity_link="http://localhost:7776/identity" +wrong_link="http://localhost:7776/identityandmore" + + +curl_get () { + #$1 is link + #$2 is grep + cache="$(curl -v "$1" 2>&1 | grep "$2")" + #echo $cache + if [ "" == "$cache" ] + then + exit 1 + fi +} + +curl_post () { + #$1 is link + #$2 is data + #$3 is grep + cache="$(curl -v -X "POST" "$1" --data "$2" 2>&1 | grep "$3")" + #echo $cache + if [ "" == "$cache" ] + then + exit 1 + fi +} + +curl_delete () { + #$1 is link + #$2 is grep + cache="$(curl -v -X "DELETE" "$1" 2>&1 | grep "$2")" + #echo $cache + if [ "" == "$cache" ] + then + exit 1 + fi +} + +curl_put () { + #$1 is link + #$2 is data + #$3 is grep + cache="$(curl -v -X "PUT" "$1" --data "$2" 2>&1 | grep "$3")" + #echo $cache + if [ "" == "$cache" ] + then + exit 1 + fi +} + +#Test GET +test="$(gnunet-identity -d)" +#if no identity exists +if [ "" == "$test" ] +then + curl_get "$identity_link/all" "error" + gnunet-identity -C "test_plugin_rest_identity" + name="$(gnunet-identity -d | awk 'NR==1{print $1}')" + public="$(gnunet-identity -d | awk 'NR==1{print $3}')" + + curl_get "${identity_link}/name/$name" "$public" + curl_get "${identity_link}/name/$public" "error" + curl_get "${identity_link}/name/" "error" + + curl_get "${identity_link}/pubkey/$public" "$name" + curl_get "${identity_link}/pubkey/$name" "error" + curl_get "${identity_link}/pubkey/" "error" + + gnunet-identity -D "test_plugin_rest_identity" +else + name="$(gnunet-identity -d | awk 'NR==1{print $1}')" + public="$(gnunet-identity -d | awk 'NR==1{print $3}')" + + curl_get "${identity_link}/name/$name" "$public" + curl_get "${identity_link}/name/$public" "error" + curl_get "${identity_link}/name/" "error" + + curl_get "${identity_link}/pubkey/$public" "$name" + curl_get "${identity_link}/pubkey/$name" "error" + curl_get "${identity_link}/pubkey/" "error" +fi + +#Test POST +gnunet-identity -D "test_plugin_rest_identity" > /dev/null 2>&1 +gnunet-identity -D "test_plugin_rest_identity1" > /dev/null 2>&1 + +curl_post "${identity_link}" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 201 Created" +curl_post "${identity_link}" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 409" +curl_post "${identity_link}" '{"name":"Test_plugin_rest_identity"}' "HTTP/1.1 409" +curl_post "${identity_link}" '{}' "error" +curl_post "${identity_link}" '' "error" +curl_post "${identity_link}" '{"name":""}' "error" +curl_post "${identity_link}" '{"name":123}' "error" +curl_post "${identity_link}" '{"name":[]}' "error" +curl_post "${identity_link}" '{"name1":"test_plugin_rest_identity"}' "error" +curl_post "${identity_link}" '{"other":""}' "error" +curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1", "other":"test_plugin_rest_identity2"}' "error" + +#Test PUT +name="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $1}')" +public="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $3}')" + +curl_put "${identity_link}/pubkey/$public" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 204" +curl_put "${identity_link}/pubkey/$public" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 409" +curl_put "${identity_link}/pubkey/${public}xx" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404" +curl_put "${identity_link}/pubkey/" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404" +curl_put "${identity_link}/pubke" '{"newname":"test_plugin_rest_identity1"}' "error" +curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","other":"sdfdsf"}' "error" +curl_put "${identity_link}/pubkey/$name" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404" +curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"test_plugin_rest_identity"}' "HTTP/1.1 204" +curl_put "${identity_link}/pubkey/$public" '{"newnam":"test_plugin_rest_identity"}' "error" +curl_put "${identity_link}/name/test_plugin_rest_identity" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 204" +curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"TEST_plugin_rest_identity1"}' "HTTP/1.1 409" +curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 409" +curl_put "${identity_link}/name/test_plugin_rest_identityxxx" '{"newname":"test_plugin_rest_identity"}' "HTTP/1.1 404" +curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"test_plugin_rest_identity"}' "HTTP/1.1 204" +curl_put "${identity_link}/name/test_plugin_rest_identity" '{"newnam":"test_plugin_rest_identityfail"}' "error" + +#Test subsystem +curl_put "${identity_link}/subsystem/test_plugin_rest_identity" '{"subsystem":"namestore"}' "HTTP/1.1 204" +curl_put "${identity_link}/subsystem/test_plugin_rest_identity" '{"subsystem":"namestore"}' "HTTP/1.1 204" +curl_get "${identity_link}/subsystem/namestore" "test_plugin_rest_identity" +public="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $3}')" +curl_put "${identity_link}/subsystem/$public" '{"subsystem":"namestore"}' "HTTP/1.1 404" +curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created" +curl_get "${identity_link}/subsystem/test_plugin_rest_identity_no_subsystem" "error" +curl_put "${identity_link}/subsystem/test_plugin_rest_identity1" '{"subsystem":"test_plugin_rest_identity_no_subsystem"}' "HTTP/1.1 204" +curl_get "${identity_link}/subsystem/test_plugin_rest_identity_no_subsystem" "test_plugin_rest_identity1" + +curl_put "${identity_link}/subsystem/test_plugin_rest_identity1" '{"subsyste":"test_plugin_rest_identity_no_subsystem"}' "error" +curl_put "${identity_link}/subsystem/test_plugin_rest_identity1" '{"subsystem":"test_plugin_rest_identity_no_subsystem"}' "HTTP/1.1 204" + +#Test DELETE +curl_delete "${identity_link}/name/test_plugin_rest_identity" "HTTP/1.1 204" +curl_get "${identity_link}/name/test_plugin_rest_identity" "error" +curl_delete "${identity_link}/name/TEST_plugin_rest_identity1" "HTTP/1.1 204" +curl_delete "${identity_link}/name/test_plugin_rest_identity1" "HTTP/1.1 404" +curl_get "${identity_link}/name/test_plugin_rest_identity1" "error" +curl_delete "${identity_link}/name/test_plugin_rest_identity_not_found" "HTTP/1.1 404" +curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created" +public="$(gnunet-identity -d | grep "test_plugin_rest_identity1" | awk 'NR==1{print $3}')" +curl_delete "${identity_link}/pubkey/$public" "HTTP/1.1 204" +curl_delete "${identity_link}/pubke/$public" "error" +curl_delete "${identity_link}/pubkey/${public}other=232" "HTTP/1.1 404" + +#Test wrong_link +curl_get "$wrong_link" "HTTP/1.1 404" +curl_post "$wrong_link" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 404" +curl_put "$wrong_link/name/test_plugin_rest_identity" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404" +curl_delete "$wrong_link/name/test_plugin_rest_identity1" "HTTP/1.1 404" + +exit 0; diff --git a/src/rest-plugins/test_plugin_rest_namestore.sh b/src/rest-plugins/test_plugin_rest_namestore.sh new file mode 100755 index 000000000..532c7caae --- /dev/null +++ b/src/rest-plugins/test_plugin_rest_namestore.sh @@ -0,0 +1,147 @@ +#!/usr/bin/bash + +#First, start gnunet-arm and the rest-service. +#Exit 0 means success, exit 1 means failed test + +namestore_link="http://localhost:7776/namestore" +wrong_link="http://localhost:7776/namestoreandmore" + + +curl_get () { + #$1 is link + #$2 is grep + cache="$(curl -v "$1" 2>&1 | grep "$2")" + echo $cache + if [ "" == "$cache" ] + then + exit 1 + fi +} + +curl_post () { + #$1 is link + #$2 is data + #$3 is grep + cache="$(curl -v -X "POST" "$1" --data "$2" 2>&1 | grep "$3")" + echo $cache + if [ "" == "$cache" ] + then + exit 1 + fi +} + +curl_delete () { + #$1 is link + #$2 is grep + cache="$(curl -v -X "DELETE" "$1" 2>&1 | grep "$2")" + echo $cache + if [ "" == "$cache" ] + then + exit 1 + fi +} + +# curl_put () { +# #$1 is link +# #$2 is data +# #$3 is grep +# cache="$(curl -v -X "PUT" "$1" --data "$2" 2>&1 | grep "$3")" +# #echo $cache +# if [ "" == "$cache" ] +# then +# exit 1 +# fi +# } + +#Test subsystem default identity + +#Test GET +gnunet-identity -D "test_plugin_rest_namestore" +gnunet-identity -C "test_plugin_rest_namestore" +test="$(gnunet-namestore -D -z "test_plugin_rest_namestore")" +name="test_plugin_rest_namestore" +public="$(gnunet-identity -d | grep "test_plugin_rest_namestore" | awk 'NR==1{print $3}')" +if [ "" == "$test" ] +then + #if no entries for test_plugin_rest_namestore + curl_get "${namestore_link}/$name" "error" + curl_get "${namestore_link}/" "error" + curl_get "${namestore_link}/$public" "error" +else + #if entries exists (that should not be possible) + curl_get "${namestore_link}" "HTTP/1.1 200 OK" + curl_get "${namestore_link}/$name" "HTTP/1.1 200 OK" + curl_get "${namestore_link}/" "error" + curl_get "${namestore_link}/$public" "error" +fi +gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" +curl_get "${namestore_link}" "HTTP/1.1 200 OK" +curl_get "${namestore_link}/$name" "HTTP/1.1 200 OK" +curl_get "${namestore_link}/" "error" +curl_get "${namestore_link}/$public" "error" +gnunet-namestore -z $name -d -n "test_entry" + +#Test POST with NAME +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +#value +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"value":"", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"value_missing":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +#time +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"0d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"10000d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"now","flag":0,"record_name":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"","flag":0,"record_name":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time_missing":"1d","flag":0,"record_name":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +#flag +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":2,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":8,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":16,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":-1,"record_name":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":"Test","record_name":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":,"record_name":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag_missing":0,"record_name":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +#record_name +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":""}' "error" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name_missing":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 + +#wrong zone +curl_post "${namestore_link}/$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 + +#Test DELETE +gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" +curl_delete "${namestore_link}/$name?record_name=test_entry" "HTTP/1.1 204" +curl_delete "${namestore_link}/$name?record_name=test_entry" "error" +gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" +curl_delete "${namestore_link}/$public?record_name=test_entry" "error" + + +#Test default identity +#not possible without defining + +exit 0; + -- cgit v1.2.3 From 8275d52ec81b53f46b799facc8c051829ded6eed Mon Sep 17 00:00:00 2001 From: Julius Bünger Date: Fri, 10 Aug 2018 12:44:51 +0200 Subject: Use synchronised logic for closing channels (rps service) --- src/cadet/Makefile.am | 12 +- src/cadet/test_cadet.c | 261 ++++++++++++++++++++++++++------- src/rps/gnunet-rps-profiler.c | 20 +-- src/rps/gnunet-service-rps.c | 248 ++++++++++--------------------- src/rps/gnunet-service-rps_custommap.c | 1 + src/rps/rps-test_util.c | 2 +- src/rps/test_rps.c | 2 +- src/rps/test_rps.conf | 1 + 8 files changed, 313 insertions(+), 234 deletions(-) (limited to 'src') diff --git a/src/cadet/Makefile.am b/src/cadet/Makefile.am index ce30ebe46..b2d436061 100644 --- a/src/cadet/Makefile.am +++ b/src/cadet/Makefile.am @@ -90,6 +90,7 @@ check_PROGRAMS = \ test_cadet_2_speed_backwards \ test_cadet_2_speed_reliable \ test_cadet_2_speed_reliable_backwards \ + test_cadet_2_reopen \ test_cadet_5_forward \ test_cadet_5_signal \ test_cadet_5_keepalive \ @@ -97,7 +98,8 @@ check_PROGRAMS = \ test_cadet_5_speed_ack \ test_cadet_5_speed_reliable \ test_cadet_5_speed_reliable_backwards \ - test_cadet_5_speed_backwards + test_cadet_5_speed_backwards \ + test_cadet_5_reopen endif @@ -197,6 +199,14 @@ test_cadet_5_speed_reliable_backwards_SOURCES = \ test_cadet.c test_cadet_5_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib) +test_cadet_2_reopen_SOURCES = \ + test_cadet.c +test_cadet_2_reopen_LDADD = $(ld_cadet_test_lib) + +test_cadet_5_reopen_SOURCES = \ + test_cadet.c +test_cadet_5_reopen_LDADD = $(ld_cadet_test_lib) + if ENABLE_TEST_RUN AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; diff --git a/src/cadet/test_cadet.c b/src/cadet/test_cadet.c index 5187bc504..76ff258e0 100644 --- a/src/cadet/test_cadet.c +++ b/src/cadet/test_cadet.c @@ -70,6 +70,7 @@ struct CadetTestChannelWrapper #define SPEED_ACK 4 #define SPEED_REL 8 #define P2P_SIGNAL 10 +#define REOPEN 11 /** * Which test are we running? @@ -176,6 +177,11 @@ struct GNUNET_CADET_TEST_Context *test_ctx; */ static struct GNUNET_SCHEDULER_Task *disconnect_task; +/** + * Task called to reconnect peers. + */ +static struct GNUNET_SCHEDULER_Task *reconnect_task; + /** * Task To perform tests */ @@ -374,7 +380,8 @@ stats_cont (void *cls, "KA sent: %u, KA received: %u\n", ka_sent, ka_received); - if ((KEEPALIVE == test) && ((ka_sent < 2) || (ka_sent > ka_received + 1))) + if ((KEEPALIVE == test || REOPEN == test) && + ((ka_sent < 2) || (ka_sent > ka_received + 1))) { GNUNET_break (0); ok--; @@ -458,6 +465,152 @@ gather_stats_and_exit (void *cls) } +/** + * Send a message on the channel with the appropriate size and payload. + * + * Update the appropriate *_sent counter. + * + * @param channel Channel to send the message on. + */ +static void +send_test_message (struct GNUNET_CADET_Channel *channel); + +/** + * Check if payload is sane (size contains payload). + * + * @param cls should match #ch + * @param message The actual message. + * @return #GNUNET_OK to keep the channel open, + * #GNUNET_SYSERR to close it (signal serious error). + */ +static int +check_data (void *cls, + const struct GNUNET_MessageHeader *message); + +/** + * Function is called whenever a message is received. + * + * @param cls closure (set from GNUNET_CADET_connect(), peer number) + * @param message the actual message + */ +static void +handle_data (void *cls, + const struct GNUNET_MessageHeader *message); + +/** + * Function called whenever an MQ-channel is destroyed, even if the destruction + * was requested by #GNUNET_CADET_channel_destroy. + * It must NOT call #GNUNET_CADET_channel_destroy on the channel. + * + * It should clean up any associated state, including cancelling any pending + * transmission on this channel. + * + * @param cls Channel closure (channel wrapper). + * @param channel Connection to the other end (henceforth invalid). + */ +static void +disconnect_handler (void *cls, + const struct GNUNET_CADET_Channel *channel); + + +/** + * Task to reconnect to other peer. + * + * @param cls Closure (line from which the task was scheduled). + */ +static void +reconnect_op (void *cls) +{ + struct GNUNET_MQ_MessageHandler handlers[] = { + GNUNET_MQ_hd_var_size (data, + GNUNET_MESSAGE_TYPE_DUMMY, + struct GNUNET_MessageHeader, + NULL), + GNUNET_MQ_handler_end () + }; + long l = (long) cls; + struct CadetTestChannelWrapper *ch; + enum GNUNET_CADET_ChannelOption flags; + + reconnect_task = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "reconnecting from line %ld\n", + l); + if (NULL != outgoing_ch) + { + GNUNET_CADET_channel_destroy (outgoing_ch); + outgoing_ch = NULL; + } + flags = GNUNET_CADET_OPTION_DEFAULT; + ch = GNUNET_new (struct CadetTestChannelWrapper); + outgoing_ch = GNUNET_CADET_channel_create (h1, + ch, + p_id[1], + &port, + flags, + NULL, + &disconnect_handler, + handlers); + ch->ch = outgoing_ch; + send_test_message (outgoing_ch); +} + +/** + * Function called whenever an MQ-channel is destroyed, even if the destruction + * was requested by #GNUNET_CADET_channel_destroy. + * It must NOT call #GNUNET_CADET_channel_destroy on the channel. + * + * It should clean up any associated state, including cancelling any pending + * transmission on this channel. + * + * @param cls Channel closure (channel wrapper). + * @param channel Connection to the other end (henceforth invalid). + */ +static void +disconnect_handler (void *cls, + const struct GNUNET_CADET_Channel *channel) +{ + struct CadetTestChannelWrapper *ch_w = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Channel disconnected at %d\n", + ok); + GNUNET_assert (ch_w->ch == channel); + if (channel == incoming_ch) + { + ok++; + incoming_ch = NULL; + } + else if (outgoing_ch == channel) + { + if (P2P_SIGNAL == test) + { + ok++; + } + outgoing_ch = NULL; + } + else + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Unknown channel! %p\n", + channel); + if (NULL != disconnect_task && REOPEN != test) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = + GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, + (void *) __LINE__); + } + else if (NULL != reconnect_task && REOPEN == test) + { + GNUNET_SCHEDULER_cancel (reconnect_task); + reconnect_task = + GNUNET_SCHEDULER_add_now (&reconnect_op, + (void *) __LINE__); + } + GNUNET_free (ch_w); +} + + /** * Abort test: schedule disconnect and shutdown immediately * @@ -536,6 +689,14 @@ send_test_message (struct GNUNET_CADET_Channel *channel) { payload = data_sent; } + else if (REOPEN == test) + { + payload = data_sent; + data_sent++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending DATA %u [%d bytes]\n", + data_sent, size); + } else { GNUNET_assert (0); @@ -784,13 +945,29 @@ connect_handler (void *cls, (long) cls); GNUNET_assert (0); } - if (NULL != disconnect_task) + if (NULL != disconnect_task && REOPEN != test) { GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time, &gather_stats_and_exit, (void *) __LINE__); } + else if ((NULL != disconnect_task) && (REOPEN == test)) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_add_delayed ( + GNUNET_TIME_relative_multiply (short_time, 2), + &gather_stats_and_exit, + (void *) __LINE__); + } + + if ((NULL != reconnect_task) && (REOPEN == test)) + { + GNUNET_SCHEDULER_cancel (reconnect_task); + reconnect_task = GNUNET_SCHEDULER_add_delayed (short_time, + &reconnect_op, + (void *) __LINE__); + } /* TODO: cannot return channel as-is, in order to unify the data handlers */ ch = GNUNET_new (struct CadetTestChannelWrapper); @@ -800,55 +977,6 @@ connect_handler (void *cls, } -/** - * Function called whenever an MQ-channel is destroyed, even if the destruction - * was requested by #GNUNET_CADET_channel_destroy. - * It must NOT call #GNUNET_CADET_channel_destroy on the channel. - * - * It should clean up any associated state, including cancelling any pending - * transmission on this channel. - * - * @param cls Channel closure (channel wrapper). - * @param channel Connection to the other end (henceforth invalid). - */ -static void -disconnect_handler (void *cls, - const struct GNUNET_CADET_Channel *channel) -{ - struct CadetTestChannelWrapper *ch_w = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Channel disconnected at %d\n", - ok); - GNUNET_assert (ch_w->ch == channel); - if (channel == incoming_ch) - { - ok++; - incoming_ch = NULL; - } - else if (outgoing_ch == channel) - { - if (P2P_SIGNAL == test) - { - ok++; - } - outgoing_ch = NULL; - } - else - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Unknown channel! %p\n", - channel); - if (NULL != disconnect_task) - { - GNUNET_SCHEDULER_cancel (disconnect_task); - disconnect_task = - GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, - (void *) __LINE__); - } - GNUNET_free (ch_w); -} - - /** * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES. * @@ -871,7 +999,7 @@ start_test (void *cls) enum GNUNET_CADET_ChannelOption flags; test_task = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "start_test\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "start_test: %s\n", test_name); if (NULL != disconnect_task) { GNUNET_SCHEDULER_cancel (disconnect_task); @@ -903,7 +1031,6 @@ start_test (void *cls) if (KEEPALIVE == test) return; /* Don't send any data. */ - data_received = 0; data_sent = 0; ack_received = 0; @@ -912,6 +1039,18 @@ start_test (void *cls) "Sending data initializer on channel %p...\n", outgoing_ch); send_test_message (outgoing_ch); + if (REOPEN == test) + { + reconnect_task = GNUNET_SCHEDULER_add_delayed (short_time, + &reconnect_op, + (void *) __LINE__); + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_add_delayed ( + GNUNET_TIME_relative_multiply (short_time, 2), + &gather_stats_and_exit, + (void *) __LINE__); + } + } @@ -1055,6 +1194,11 @@ main (int argc, char *argv[]) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "5 PEER LINE\n"); peers_requested = 5; } + else if (strstr (argv[0], "_6_") != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "6 PEER LINE\n"); + peers_requested = 6; + } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SIZE UNKNOWN, USING 2\n"); @@ -1122,6 +1266,17 @@ main (int argc, char *argv[]) */ ok_goal = 2; } + else if (strstr (argv[0], "_reopen") != NULL) + { + test = REOPEN; + test_name = "reopen"; + ///* Test is supposed to generate the following callbacks: + // * 1 incoming channel (@dest) + // * [wait] + // * 1 received channel destroy (@dest) + // */ + ok_goal = 7; + } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n"); diff --git a/src/rps/gnunet-rps-profiler.c b/src/rps/gnunet-rps-profiler.c index 49714872f..277688b56 100644 --- a/src/rps/gnunet-rps-profiler.c +++ b/src/rps/gnunet-rps-profiler.c @@ -2311,14 +2311,14 @@ void write_final_stats (void){ for (uint32_t i = 0; i < num_peers; i++) { - to_file ("/tmp/rps/final_stats.dat", - "%" PRIu32 " " /* index */ - "%s %" /* id */ - PRIu64 " %" /* rounds */ - PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" /* blocking */ - PRIu64 " %" PRIu64 " %" PRIu64 " %" /* issued */ - PRIu64 " %" PRIu64 " %" PRIu64 " %" /* sent */ - PRIu64 " %" PRIu64 " %" PRIu64 /* recv */, + to_file ("/tmp/rps/final_stats.csv", + ", %" PRIu32 ", " /* index */ + "%s, %" /* id */ + PRIu64 ", %" /* rounds */ + PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" /* blocking */ + PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" /* issued */ + PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" /* sent */ + PRIu64 ", %" PRIu64 ", %" PRIu64 /* recv */, i, GNUNET_i2s (rps_peers[i].peer_id), rps_peers[i].stats[STAT_TYPE_ROUNDS], @@ -2407,10 +2407,10 @@ post_test_shutdown_ready_cb (void *cls, GNUNET_TESTBED_operation_done (rps_peer->stat_op); } - write_final_stats (); + //write_final_stats (); if (GNUNET_YES == check_statistics_collect_completed()) { - //write_final_stats (); + write_final_stats (); GNUNET_free (stat_cls); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down\n"); diff --git a/src/rps/gnunet-service-rps.c b/src/rps/gnunet-service-rps.c index 6b0ecc58c..8e8320a53 100644 --- a/src/rps/gnunet-service-rps.c +++ b/src/rps/gnunet-service-rps.c @@ -232,11 +232,6 @@ struct PeerContext struct PendingMessage *pending_messages_head; struct PendingMessage *pending_messages_tail; - /** - * @brief Task to destroy this context. - */ - struct GNUNET_SCHEDULER_Task *destruction_task; - /** * This is pobably followed by 'statistical' data (when we first saw * it, how did we get its ID, how many pushes (in a timeinterval), @@ -280,11 +275,6 @@ struct ChannelCtx * @brief The peer context associated with the channel */ struct PeerContext *peer_ctx; - - /** - * @brief Scheduled task that will destroy this context - */ - struct GNUNET_SCHEDULER_Task *destruction_task; }; /** @@ -335,8 +325,28 @@ get_peer_ctx (const struct GNUNET_PeerIdentity *peer) return ctx; } -int -Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer); +/** + * @brief Check whether we have information about the given peer. + * + * FIXME probably deprecated. Make this the new _online. + * + * @param peer peer in question + * + * @return #GNUNET_YES if peer is known + * #GNUNET_NO if peer is not knwon + */ +static int +Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer) +{ + if (NULL != peer_map) + { + return GNUNET_CONTAINER_multipeermap_contains (peer_map, peer); + } else + { + return GNUNET_NO; + } +} + /** * @brief Create a new #PeerContext and insert it into the peer map @@ -379,11 +389,37 @@ create_or_get_peer_ctx (const struct GNUNET_PeerIdentity *peer) return get_peer_ctx (peer); } -void -Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags); -void -Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags); +/** + * @brief unset flags on a given peer. + * + * @param peer the peer to unset flags on + * @param flags the flags + */ +static void +Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags) +{ + struct PeerContext *peer_ctx; + + peer_ctx = get_peer_ctx (peer); + unset_peer_flag (peer_ctx, flags); +} + + +/** + * @brief set flags on a given peer. + * + * @param peer the peer to set flags on + * @param flags the flags + */ +static void +Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags) +{ + struct PeerContext *peer_ctx; + + peer_ctx = get_peer_ctx (peer); + set_peer_flag (peer_ctx, flags); +} /** * @brief Check whether we have a connection to this @a peer @@ -395,7 +431,7 @@ Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlag * @return #GNUNET_YES if we are connected * #GNUNET_NO otherwise */ -int +static int Peers_check_connected (const struct GNUNET_PeerIdentity *peer) { const struct PeerContext *peer_ctx; @@ -1084,7 +1120,7 @@ restore_valid_peers () * @param cadet_h cadet handle * @param own_id own peer identity */ -void +static void Peers_initialise (char* fn_valid_peers, struct GNUNET_CADET_Handle *cadet_h) { @@ -1150,7 +1186,7 @@ valid_peer_iterator (void *cls, * @return the number of key value pairs processed, * #GNUNET_SYSERR if it aborted iteration */ -int +static int Peers_get_valid_peers (PeersIterator iterator, void *it_cls) { @@ -1179,7 +1215,7 @@ Peers_get_valid_peers (PeersIterator iterator, * @return #GNUNET_YES if peer was inserted * #GNUNET_NO otherwise */ -int +static int Peers_insert_peer (const struct GNUNET_PeerIdentity *peer) { if (GNUNET_YES == Peers_check_peer_known (peer)) @@ -1190,7 +1226,7 @@ Peers_insert_peer (const struct GNUNET_PeerIdentity *peer) return GNUNET_YES; } -int +static int Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags); /** @@ -1202,7 +1238,7 @@ Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFl * @return #GNUNET_YES if peer had to be inserted * #GNUNET_NO otherwise */ -int +static int Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer) { struct PeerContext *peer_ctx; @@ -1232,7 +1268,7 @@ Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer) * #GNUNET_NO if peer is NOT removable * #GNUNET_SYSERR if peer is not known */ -int +static int Peers_check_removable (const struct GNUNET_PeerIdentity *peer) { struct PeerContext *peer_ctx; @@ -1252,11 +1288,11 @@ Peers_check_removable (const struct GNUNET_PeerIdentity *peer) return GNUNET_YES; } -uint32_t * +static uint32_t * Peers_get_channel_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_ChannelRole role); -int +static int Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags); /** @@ -1270,54 +1306,26 @@ destroy_peer (void *cls) struct PeerContext *peer_ctx = cls; GNUNET_assert (NULL != peer_ctx); - peer_ctx->destruction_task = NULL; Peers_remove_peer (&peer_ctx->peer_id); } -static void -destroy_channel (void *cls); - - /** - * @brief Schedule the destruction of the given channel. - * - * Do so only if it was not already scheduled and not during shutdown. + * @brief Callback for scheduler to destroy a channel * - * @param channel_ctx The context of the channel to destroy. + * @param cls Context of the channel */ static void -schedule_channel_destruction (struct ChannelCtx *channel_ctx) +destroy_channel (void *cls) { - GNUNET_assert (NULL != channel_ctx); - if (NULL != channel_ctx->destruction_task && - GNUNET_NO == in_shutdown) - { - channel_ctx->destruction_task = - GNUNET_SCHEDULER_add_now (&destroy_channel, - channel_ctx); - } -} + struct ChannelCtx *channel_ctx = cls; + struct PeerContext *peer_ctx = channel_ctx->peer_ctx; + GNUNET_assert (channel_ctx == peer_ctx->send_channel_ctx || + channel_ctx == peer_ctx->recv_channel_ctx); -/** - * @brief Schedule the destruction of the given peer. - * - * Do so only if it was not already scheduled and not during shutdown. - * - * @param peer_ctx The context of the peer to destroy. - */ -static void -schedule_peer_destruction (struct PeerContext *peer_ctx) -{ - GNUNET_assert (NULL != peer_ctx); - if (NULL != peer_ctx->destruction_task && - GNUNET_NO == in_shutdown) - { - peer_ctx->destruction_task = - GNUNET_SCHEDULER_add_now (&destroy_peer, - peer_ctx); - } + GNUNET_CADET_channel_destroy (channel_ctx->channel); + remove_channel_ctx (peer_ctx->send_channel_ctx); } @@ -1389,35 +1397,17 @@ Peers_remove_peer (const struct GNUNET_PeerIdentity *peer) /* Do we still have to wait for destruction of channels * or issue the destruction? */ - if (NULL != peer_ctx->send_channel_ctx && - NULL != peer_ctx->send_channel_ctx->destruction_task) - { - schedule_peer_destruction (peer_ctx); - return GNUNET_NO; - } - if (NULL != peer_ctx->recv_channel_ctx && - NULL != peer_ctx->recv_channel_ctx->destruction_task) + if (NULL != peer_ctx->send_channel_ctx) { - schedule_peer_destruction (peer_ctx); + destroy_channel (peer_ctx->send_channel_ctx); return GNUNET_NO; } if (NULL != peer_ctx->recv_channel_ctx) { - schedule_channel_destruction (peer_ctx->recv_channel_ctx); - schedule_peer_destruction (peer_ctx); - return GNUNET_NO; - } - if (NULL != peer_ctx->send_channel_ctx) - { - schedule_channel_destruction (peer_ctx->send_channel_ctx); - schedule_peer_destruction (peer_ctx); + destroy_channel (peer_ctx->recv_channel_ctx); return GNUNET_NO; } - - if (NULL != peer_ctx->destruction_task) - { - GNUNET_SCHEDULER_cancel (peer_ctx->destruction_task); - } + destroy_peer (peer_ctx); if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove_all (peer_map, @@ -1431,38 +1421,6 @@ Peers_remove_peer (const struct GNUNET_PeerIdentity *peer) } -/** - * @brief set flags on a given peer. - * - * @param peer the peer to set flags on - * @param flags the flags - */ -void -Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags) -{ - struct PeerContext *peer_ctx; - - peer_ctx = get_peer_ctx (peer); - set_peer_flag (peer_ctx, flags); -} - - -/** - * @brief unset flags on a given peer. - * - * @param peer the peer to unset flags on - * @param flags the flags - */ -void -Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags) -{ - struct PeerContext *peer_ctx; - - peer_ctx = get_peer_ctx (peer); - unset_peer_flag (peer_ctx, flags); -} - - /** * @brief Check whether flags on a peer are set. * @@ -1473,7 +1431,7 @@ Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFl * #GNUNET_YES if all given flags are set * #GNUNET_NO otherwise */ -int +static int Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags) { struct PeerContext *peer_ctx; @@ -1486,28 +1444,6 @@ Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFl return check_peer_flag_set (peer_ctx, flags); } -/** - * @brief Check whether we have information about the given peer. - * - * FIXME probably deprecated. Make this the new _online. - * - * @param peer peer in question - * - * @return #GNUNET_YES if peer is known - * #GNUNET_NO if peer is not knwon - */ -int -Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer) -{ - if (NULL != peer_map) - { - return GNUNET_CONTAINER_multipeermap_contains (peer_map, peer); - } else - { - return GNUNET_NO; - } -} - /** * @brief Check whether @a peer is actually a peer. @@ -1519,7 +1455,7 @@ Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer) * @return #GNUNET_YES if peer is valid * #GNUNET_NO if peer is not valid */ -int +static int Peers_check_peer_valid (const struct GNUNET_PeerIdentity *peer) { return GNUNET_CONTAINER_multipeermap_contains (valid_peers, peer); @@ -1533,7 +1469,7 @@ Peers_check_peer_valid (const struct GNUNET_PeerIdentity *peer) * * @param peer the peer to establish channel to */ -void +static void Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer) { GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer)); @@ -1702,33 +1638,13 @@ Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer) peer_ctx = get_peer_ctx (peer); if (NULL != peer_ctx->send_channel_ctx) { - schedule_channel_destruction (peer_ctx->send_channel_ctx); + destroy_channel (peer_ctx->send_channel_ctx); (void) Peers_check_connected (peer); return GNUNET_YES; } return GNUNET_NO; } -/** - * @brief Callback for scheduler to destroy a channel - * - * @param cls Context of the channel - */ -static void -destroy_channel (void *cls) -{ - struct ChannelCtx *channel_ctx = cls; - struct PeerContext *peer_ctx = channel_ctx->peer_ctx; - - GNUNET_assert (channel_ctx == peer_ctx->send_channel_ctx || - channel_ctx == peer_ctx->recv_channel_ctx); - - channel_ctx->destruction_task = NULL; - GNUNET_CADET_channel_destroy (channel_ctx->channel); - remove_channel_ctx (peer_ctx->send_channel_ctx); -} - - /** * @brief Send a message to another peer. * @@ -2605,7 +2521,7 @@ remove_peer (const struct GNUNET_PeerIdentity *peer) CustomPeerMap_remove_peer (push_map, peer); RPS_sampler_reinitialise_by_value (prot_sampler, peer); RPS_sampler_reinitialise_by_value (client_sampler, peer); - schedule_peer_destruction (get_peer_ctx (peer)); + destroy_peer (get_peer_ctx (peer)); } @@ -2675,10 +2591,6 @@ remove_channel_ctx (struct ChannelCtx *channel_ctx) { struct PeerContext *peer_ctx = channel_ctx->peer_ctx; - if (NULL != channel_ctx->destruction_task) - { - GNUNET_SCHEDULER_cancel (channel_ctx->destruction_task); - } GNUNET_free (channel_ctx); if (channel_ctx == peer_ctx->send_channel_ctx) { @@ -4098,7 +4010,7 @@ shutdown_task (void *cls) do_round_task = NULL; } - Peers_terminate (); + peers_terminate (); GNUNET_NSE_disconnect (nse); RPS_sampler_destroy (prot_sampler); diff --git a/src/rps/gnunet-service-rps_custommap.c b/src/rps/gnunet-service-rps_custommap.c index 9e003eb39..3513ff8da 100644 --- a/src/rps/gnunet-service-rps_custommap.c +++ b/src/rps/gnunet-service-rps_custommap.c @@ -202,6 +202,7 @@ CustomPeerMap_remove_peer (const struct CustomPeerMap *c_peer_map, p = GNUNET_CONTAINER_multihashmap32_get (c_peer_map->hash_map, *index); GNUNET_assert (NULL != p); GNUNET_CONTAINER_multihashmap32_remove_all (c_peer_map->hash_map, *index); + // TODO wrong peerid? GNUNET_CONTAINER_multipeermap_remove_all (c_peer_map->peer_map, peer); if (*index != CustomPeerMap_size (c_peer_map)) { /* fill 'gap' with peer at last index */ diff --git a/src/rps/rps-test_util.c b/src/rps/rps-test_util.c index 08fe96097..ed682c251 100644 --- a/src/rps/rps-test_util.c +++ b/src/rps/rps-test_util.c @@ -239,7 +239,7 @@ to_file_raw_unaligned (const char *file_name, /* needed bits of the input byte that have not been moved */ char byte_input_leftover; unsigned num_bits_leftover; - unsigned num_bits_discard; + //unsigned num_bits_discard; char byte_unaligned_new; if ( (bits_needed - (i * 8)) <= 8) diff --git a/src/rps/test_rps.c b/src/rps/test_rps.c index 08424022f..92d8c12ea 100644 --- a/src/rps/test_rps.c +++ b/src/rps/test_rps.c @@ -2850,7 +2850,7 @@ main (int argc, char *argv[]) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "This is the profiler\n"); cur_test_run.name = "test-rps-profiler"; - num_peers = 100; + num_peers = 16; mal_type = 3; cur_test_run.init_peer = profiler_init_peer; //cur_test_run.pre_test = mal_pre; diff --git a/src/rps/test_rps.conf b/src/rps/test_rps.conf index 05bb9f444..02fbf76a4 100644 --- a/src/rps/test_rps.conf +++ b/src/rps/test_rps.conf @@ -1,5 +1,6 @@ [rps] #PREFIX = valgrind --leak-check=full --show-leak-kinds=all --log-file=/tmp/rps/valgrind!gnunet-service-rps!%p +#PREFIX = valgrind --log-file=/tmp/rps/valgrind!gnunet-service-rps!%p #BINARY = gnunet-service-rps UNIXPATH = $GNUNET_TMP/gnunet-service-rps.sock HOME = $SERVICEHOME -- cgit v1.2.3 From 0d0cf87380b06ee7a268bb5326787a12b17fbafe Mon Sep 17 00:00:00 2001 From: Julius Bünger Date: Fri, 10 Aug 2018 12:50:39 +0200 Subject: Make non-exported functions static --- src/rps/gnunet-service-rps.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/rps/gnunet-service-rps.c b/src/rps/gnunet-service-rps.c index 8e8320a53..807e2bc12 100644 --- a/src/rps/gnunet-service-rps.c +++ b/src/rps/gnunet-service-rps.c @@ -1486,7 +1486,7 @@ Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer) * @return #GNUNET_YES if peer has the intention to send * #GNUNET_NO otherwise */ -int +static int Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer) { const struct PeerContext *peer_ctx; @@ -1510,7 +1510,7 @@ Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer) * @return initial channel context for the channel * (can be NULL -- that's not an error) */ -void * +static void * Peers_handle_inbound_channel (void *cls, struct GNUNET_CADET_Channel *channel, const struct GNUNET_PeerIdentity *initiator) @@ -1556,7 +1556,7 @@ Peers_handle_inbound_channel (void *cls, * @return #GNUNET_YES if a sending channel towards that peer exists * #GNUNET_NO otherwise */ -int +static int Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer) { struct PeerContext *peer_ctx; @@ -1586,7 +1586,7 @@ Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer) * @return #GNUNET_YES if the given chennel is the sending channel of the peer * #GNUNET_NO otherwise */ -int +static int Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_CADET_Channel *channel, enum Peers_ChannelRole role) @@ -1626,7 +1626,7 @@ Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer, * @return #GNUNET_YES if channel was destroyed * #GNUNET_NO otherwise */ -int +static int Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer) { struct PeerContext *peer_ctx; @@ -1655,7 +1655,7 @@ Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer) * @param ev envelope of the message * @param type type of the message */ -void +static void Peers_send_message (const struct GNUNET_PeerIdentity *peer, struct GNUNET_MQ_Envelope *ev, const char *type) @@ -1685,7 +1685,7 @@ Peers_send_message (const struct GNUNET_PeerIdentity *peer, * @return #GNUNET_YES if the operation was scheduled * #GNUNET_NO otherwise */ -int +static int Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer, const PeerOp peer_op) { @@ -1718,7 +1718,7 @@ Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer, * * @return The recv_channel. */ -struct GNUNET_CADET_Channel * +static struct GNUNET_CADET_Channel * Peers_get_recv_channel (const struct GNUNET_PeerIdentity *peer) { struct PeerContext *peer_ctx; -- cgit v1.2.3 From be3250261ec4a398feecf23dca236ab847515d8e Mon Sep 17 00:00:00 2001 From: Julius Bünger Date: Mon, 13 Aug 2018 14:32:07 +0200 Subject: Refactor, simplify, delete code --- src/rps/gnunet-service-rps.c | 611 +++++++++++++++++-------------------------- 1 file changed, 234 insertions(+), 377 deletions(-) (limited to 'src') diff --git a/src/rps/gnunet-service-rps.c b/src/rps/gnunet-service-rps.c index 807e2bc12..18b9b792b 100644 --- a/src/rps/gnunet-service-rps.c +++ b/src/rps/gnunet-service-rps.c @@ -84,7 +84,7 @@ static struct GNUNET_HashCode port; /** * Set a peer flag of given peer context. */ -#define set_peer_flag(peer_ctx, mask) ((peer_ctx->peer_flags) |= (mask)) +#define SET_PEER_FLAG(peer_ctx, mask) ((peer_ctx->peer_flags) |= (mask)) /** * Get peer flag of given peer context. @@ -95,7 +95,7 @@ static struct GNUNET_HashCode port; /** * Unset flag of given peer context. */ -#define unset_peer_flag(peer_ctx, mask) ((peer_ctx->peer_flags) &= ~(mask)) +#define UNSET_PEER_FLAG(peer_ctx, mask) ((peer_ctx->peer_flags) &= ~(mask)) /** * Get channel flag of given channel context. @@ -336,7 +336,7 @@ get_peer_ctx (const struct GNUNET_PeerIdentity *peer) * #GNUNET_NO if peer is not knwon */ static int -Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer) +check_peer_known (const struct GNUNET_PeerIdentity *peer) { if (NULL != peer_map) { @@ -361,7 +361,7 @@ create_peer_ctx (const struct GNUNET_PeerIdentity *peer) struct PeerContext *ctx; int ret; - GNUNET_assert (GNUNET_NO == Peers_check_peer_known (peer)); + GNUNET_assert (GNUNET_NO == check_peer_known (peer)); ctx = GNUNET_new (struct PeerContext); ctx->peer_id = *peer; @@ -382,7 +382,7 @@ create_peer_ctx (const struct GNUNET_PeerIdentity *peer) static struct PeerContext * create_or_get_peer_ctx (const struct GNUNET_PeerIdentity *peer) { - if (GNUNET_NO == Peers_check_peer_known (peer)) + if (GNUNET_NO == check_peer_known (peer)) { return create_peer_ctx (peer); } @@ -390,37 +390,6 @@ create_or_get_peer_ctx (const struct GNUNET_PeerIdentity *peer) } -/** - * @brief unset flags on a given peer. - * - * @param peer the peer to unset flags on - * @param flags the flags - */ -static void -Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags) -{ - struct PeerContext *peer_ctx; - - peer_ctx = get_peer_ctx (peer); - unset_peer_flag (peer_ctx, flags); -} - - -/** - * @brief set flags on a given peer. - * - * @param peer the peer to set flags on - * @param flags the flags - */ -static void -Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags) -{ - struct PeerContext *peer_ctx; - - peer_ctx = get_peer_ctx (peer); - set_peer_flag (peer_ctx, flags); -} - /** * @brief Check whether we have a connection to this @a peer * @@ -432,12 +401,12 @@ Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlag * #GNUNET_NO otherwise */ static int -Peers_check_connected (const struct GNUNET_PeerIdentity *peer) +check_connected (const struct GNUNET_PeerIdentity *peer) { - const struct PeerContext *peer_ctx; + struct PeerContext *peer_ctx; /* If we don't know about this peer we don't know whether it's online */ - if (GNUNET_NO == Peers_check_peer_known (peer)) + if (GNUNET_NO == check_peer_known (peer)) { return GNUNET_NO; } @@ -447,11 +416,11 @@ Peers_check_connected (const struct GNUNET_PeerIdentity *peer) if ( (NULL == peer_ctx->send_channel_ctx) && (NULL == peer_ctx->recv_channel_ctx) ) { - Peers_unset_peer_flag (peer, Peers_ONLINE); + UNSET_PEER_FLAG (peer_ctx, Peers_ONLINE); return GNUNET_NO; } /* Otherwise (if we have a channel, we know that it's online */ - Peers_set_peer_flag (peer, Peers_ONLINE); + SET_PEER_FLAG (peer_ctx, Peers_ONLINE); return GNUNET_YES; } @@ -595,7 +564,7 @@ set_peer_live (struct PeerContext *peer_ctx) } (void) add_valid_peer (peer); - set_peer_flag (peer_ctx, Peers_ONLINE); + SET_PEER_FLAG (peer_ctx, Peers_ONLINE); /* Call pending operations */ for (i = 0; i < peer_ctx->num_pending_ops; i++) @@ -640,7 +609,14 @@ handle_peer_pull_reply (void *cls, * @return The channel context */ static struct ChannelCtx * -add_channel_ctx (struct PeerContext *peer_ctx); +add_channel_ctx (struct PeerContext *peer_ctx) +{ + struct ChannelCtx *channel_ctx; + channel_ctx = GNUNET_new (struct ChannelCtx); + channel_ctx->peer_ctx = peer_ctx; + return channel_ctx; +} + /** * @brief Remove the channel context from the DLL and free the memory. @@ -648,7 +624,26 @@ add_channel_ctx (struct PeerContext *peer_ctx); * @param channel_ctx The channel context. */ static void -remove_channel_ctx (struct ChannelCtx *channel_ctx); +remove_channel_ctx (struct ChannelCtx *channel_ctx) +{ + struct PeerContext *peer_ctx = channel_ctx->peer_ctx; + + if (channel_ctx == peer_ctx->send_channel_ctx) + { + GNUNET_free (channel_ctx); + peer_ctx->send_channel_ctx = NULL; + peer_ctx->mq = NULL; + } + else if (channel_ctx == peer_ctx->recv_channel_ctx) + { + GNUNET_free (channel_ctx); + peer_ctx->recv_channel_ctx = NULL; + } + else + { + GNUNET_assert (0); + } +} /** @@ -859,8 +854,107 @@ check_operation_scheduled (const struct GNUNET_PeerIdentity *peer, return GNUNET_NO; } +/** + * @brief Callback for scheduler to destroy a channel + * + * @param cls Context of the channel + */ +static void +destroy_channel (struct ChannelCtx *channel_ctx) +{ + struct PeerContext *peer_ctx = channel_ctx->peer_ctx; + + GNUNET_assert (channel_ctx == peer_ctx->send_channel_ctx || + channel_ctx == peer_ctx->recv_channel_ctx); + + GNUNET_CADET_channel_destroy (channel_ctx->channel); + remove_channel_ctx (channel_ctx); +} + + +/** + * @brief Remove peer + * + * @param peer the peer to clean + * @return #GNUNET_YES if peer was removed + * #GNUNET_NO otherwise + */ static int -Peers_remove_peer (const struct GNUNET_PeerIdentity *peer); +destroy_peer (struct PeerContext *peer_ctx) +{ + GNUNET_assert (NULL != peer_ctx); + GNUNET_assert (NULL != peer_map); + if (GNUNET_NO == + GNUNET_CONTAINER_multipeermap_contains (peer_map, + &peer_ctx->peer_id)) + { + return GNUNET_NO; + } + SET_PEER_FLAG (peer_ctx, Peers_TO_DESTROY); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Going to remove peer %s\n", + GNUNET_i2s (&peer_ctx->peer_id)); + UNSET_PEER_FLAG (peer_ctx, Peers_ONLINE); + + /* Clear list of pending operations */ + // TODO this probably leaks memory + // ('only' the cls to the function. Not sure what to do with it) + GNUNET_array_grow (peer_ctx->pending_ops, + peer_ctx->num_pending_ops, + 0); + /* Remove all pending messages */ + while (NULL != peer_ctx->pending_messages_head) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Removing unsent %s\n", + peer_ctx->pending_messages_head->type); + /* Cancle pending message, too */ + if ( (NULL != peer_ctx->liveliness_check_pending) && + (0 == memcmp (peer_ctx->pending_messages_head, + peer_ctx->liveliness_check_pending, + sizeof (struct PendingMessage))) ) + { + // TODO this may leak memory + peer_ctx->liveliness_check_pending = NULL; + } + remove_pending_message (peer_ctx->pending_messages_head, + GNUNET_YES); + } + + /* If we are still waiting for notification whether this peer is live + * cancel the according task */ + if (NULL != peer_ctx->liveliness_check_pending) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Removing pending liveliness check for peer %s\n", + GNUNET_i2s (&peer_ctx->peer_id)); + // TODO wait until cadet sets mq->cancel_impl + //GNUNET_MQ_send_cancel (peer_ctx->liveliness_check_pending->ev); + remove_pending_message (peer_ctx->liveliness_check_pending, + GNUNET_YES); + peer_ctx->liveliness_check_pending = NULL; + } + + if (NULL != peer_ctx->send_channel_ctx) + { + destroy_channel (peer_ctx->send_channel_ctx); + } + if (NULL != peer_ctx->recv_channel_ctx) + { + destroy_channel (peer_ctx->recv_channel_ctx); + } + + if (GNUNET_YES != + GNUNET_CONTAINER_multipeermap_remove_all (peer_map, + &peer_ctx->peer_id)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + "removing peer from peer_map failed\n"); + } + GNUNET_free (peer_ctx); + return GNUNET_YES; +} + /** * Iterator over hash map entries. Deletes all contexts of peers. @@ -876,7 +970,7 @@ peermap_clear_iterator (void *cls, const struct GNUNET_PeerIdentity *key, void *value) { - Peers_remove_peer (key); + destroy_peer (get_peer_ctx (key)); return GNUNET_YES; } @@ -1121,7 +1215,7 @@ restore_valid_peers () * @param own_id own peer identity */ static void -Peers_initialise (char* fn_valid_peers, +initialise_peers (char* fn_valid_peers, struct GNUNET_CADET_Handle *cadet_h) { filename_valid_peers = GNUNET_strdup (fn_valid_peers); @@ -1133,7 +1227,7 @@ Peers_initialise (char* fn_valid_peers, /** - * @brief Delete storage of peers that was created with #Peers_initialise () + * @brief Delete storage of peers that was created with #initialise_peers () */ static void peers_terminate () @@ -1187,8 +1281,8 @@ valid_peer_iterator (void *cls, * #GNUNET_SYSERR if it aborted iteration */ static int -Peers_get_valid_peers (PeersIterator iterator, - void *it_cls) +get_valid_peers (PeersIterator iterator, + void *it_cls) { struct PeersIteratorCls *cls; int ret; @@ -1216,9 +1310,9 @@ Peers_get_valid_peers (PeersIterator iterator, * #GNUNET_NO otherwise */ static int -Peers_insert_peer (const struct GNUNET_PeerIdentity *peer) +insert_peer (const struct GNUNET_PeerIdentity *peer) { - if (GNUNET_YES == Peers_check_peer_known (peer)) + if (GNUNET_YES == check_peer_known (peer)) { return GNUNET_NO; /* We already know this peer - nothing to do */ } @@ -1226,8 +1320,30 @@ Peers_insert_peer (const struct GNUNET_PeerIdentity *peer) return GNUNET_YES; } + +/** + * @brief Check whether flags on a peer are set. + * + * @param peer the peer to check the flag of + * @param flags the flags to check + * + * @return #GNUNET_SYSERR if peer is not known + * #GNUNET_YES if all given flags are set + * #GNUNET_NO otherwise + */ static int -Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags); +check_peer_flag (const struct GNUNET_PeerIdentity *peer, + enum Peers_PeerFlags flags) +{ + struct PeerContext *peer_ctx; + + if (GNUNET_NO == check_peer_known (peer)) + { + return GNUNET_SYSERR; + } + peer_ctx = get_peer_ctx (peer); + return check_peer_flag_set (peer_ctx, flags); +} /** * @brief Try connecting to a peer to see whether it is online @@ -1239,14 +1355,14 @@ Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFl * #GNUNET_NO otherwise */ static int -Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer) +issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer) { struct PeerContext *peer_ctx; int ret; - ret = Peers_insert_peer (peer); + ret = insert_peer (peer); peer_ctx = get_peer_ctx (peer); - if ( (GNUNET_NO == Peers_check_peer_flag (peer, Peers_ONLINE)) && + if ( (GNUNET_NO == check_peer_flag (peer, Peers_ONLINE)) && (NULL == peer_ctx->liveliness_check_pending) ) { check_peer_live (peer_ctx); @@ -1269,7 +1385,7 @@ Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer) * #GNUNET_SYSERR if peer is not known */ static int -Peers_check_removable (const struct GNUNET_PeerIdentity *peer) +check_removable (const struct GNUNET_PeerIdentity *peer) { struct PeerContext *peer_ctx; @@ -1288,162 +1404,6 @@ Peers_check_removable (const struct GNUNET_PeerIdentity *peer) return GNUNET_YES; } -static uint32_t * -Peers_get_channel_flag (const struct GNUNET_PeerIdentity *peer, - enum Peers_ChannelRole role); - -static int -Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags); - -/** - * @brief Callback for the scheduler to destroy the knowledge of a peer. - * - * @param cls Context of the peer - */ -static void -destroy_peer (void *cls) -{ - struct PeerContext *peer_ctx = cls; - - GNUNET_assert (NULL != peer_ctx); - Peers_remove_peer (&peer_ctx->peer_id); -} - - -/** - * @brief Callback for scheduler to destroy a channel - * - * @param cls Context of the channel - */ -static void -destroy_channel (void *cls) -{ - struct ChannelCtx *channel_ctx = cls; - struct PeerContext *peer_ctx = channel_ctx->peer_ctx; - - GNUNET_assert (channel_ctx == peer_ctx->send_channel_ctx || - channel_ctx == peer_ctx->recv_channel_ctx); - - GNUNET_CADET_channel_destroy (channel_ctx->channel); - remove_channel_ctx (peer_ctx->send_channel_ctx); -} - - -/** - * @brief Remove peer - * - * @param peer the peer to clean - * @return #GNUNET_YES if peer was removed - * #GNUNET_NO otherwise - */ -static int -Peers_remove_peer (const struct GNUNET_PeerIdentity *peer) -{ - struct PeerContext *peer_ctx; - - GNUNET_assert (NULL != peer_map); - if (GNUNET_NO == - GNUNET_CONTAINER_multipeermap_contains (peer_map, - peer)) - { - return GNUNET_NO; - } - peer_ctx = get_peer_ctx (peer); - set_peer_flag (peer_ctx, Peers_TO_DESTROY); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Going to remove peer %s\n", - GNUNET_i2s (&peer_ctx->peer_id)); - Peers_unset_peer_flag (peer, Peers_ONLINE); - - /* Clear list of pending operations */ - // TODO this probably leaks memory - // ('only' the cls to the function. Not sure what to do with it) - GNUNET_array_grow (peer_ctx->pending_ops, - peer_ctx->num_pending_ops, - 0); - /* Remove all pending messages */ - while (NULL != peer_ctx->pending_messages_head) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Removing unsent %s\n", - peer_ctx->pending_messages_head->type); - /* Cancle pending message, too */ - if ( (NULL != peer_ctx->liveliness_check_pending) && - (0 == memcmp (peer_ctx->pending_messages_head, - peer_ctx->liveliness_check_pending, - sizeof (struct PendingMessage))) ) - { - // TODO this may leak memory - peer_ctx->liveliness_check_pending = NULL; - } - remove_pending_message (peer_ctx->pending_messages_head, - GNUNET_YES); - } - - /* If we are still waiting for notification whether this peer is live - * cancel the according task */ - if (NULL != peer_ctx->liveliness_check_pending) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Removing pending liveliness check for peer %s\n", - GNUNET_i2s (&peer_ctx->peer_id)); - // TODO wait until cadet sets mq->cancel_impl - //GNUNET_MQ_send_cancel (peer_ctx->liveliness_check_pending->ev); - remove_pending_message (peer_ctx->liveliness_check_pending, - GNUNET_YES); - peer_ctx->liveliness_check_pending = NULL; - } - - - /* Do we still have to wait for destruction of channels - * or issue the destruction? */ - if (NULL != peer_ctx->send_channel_ctx) - { - destroy_channel (peer_ctx->send_channel_ctx); - return GNUNET_NO; - } - if (NULL != peer_ctx->recv_channel_ctx) - { - destroy_channel (peer_ctx->recv_channel_ctx); - return GNUNET_NO; - } - destroy_peer (peer_ctx); - - if (GNUNET_YES != - GNUNET_CONTAINER_multipeermap_remove_all (peer_map, - &peer_ctx->peer_id)) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "removing peer from peer_map failed\n"); - } - GNUNET_free (peer_ctx); - return GNUNET_YES; -} - - -/** - * @brief Check whether flags on a peer are set. - * - * @param peer the peer to check the flag of - * @param flags the flags to check - * - * @return #GNUNET_SYSERR if peer is not known - * #GNUNET_YES if all given flags are set - * #GNUNET_NO otherwise - */ -static int -Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags) -{ - struct PeerContext *peer_ctx; - - if (GNUNET_NO == Peers_check_peer_known (peer)) - { - return GNUNET_SYSERR; - } - peer_ctx = get_peer_ctx (peer); - return check_peer_flag_set (peer_ctx, flags); -} - /** * @brief Check whether @a peer is actually a peer. @@ -1456,7 +1416,7 @@ Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFl * #GNUNET_NO if peer is not valid */ static int -Peers_check_peer_valid (const struct GNUNET_PeerIdentity *peer) +check_peer_valid (const struct GNUNET_PeerIdentity *peer) { return GNUNET_CONTAINER_multipeermap_contains (valid_peers, peer); } @@ -1470,9 +1430,9 @@ Peers_check_peer_valid (const struct GNUNET_PeerIdentity *peer) * @param peer the peer to establish channel to */ static void -Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer) +indicate_sending_intention (const struct GNUNET_PeerIdentity *peer) { - GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer)); + GNUNET_assert (GNUNET_YES == check_peer_known (peer)); (void) get_channel (peer); } @@ -1487,7 +1447,7 @@ Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer) * #GNUNET_NO otherwise */ static int -Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer) +check_peer_send_intention (const struct GNUNET_PeerIdentity *peer) { const struct PeerContext *peer_ctx; @@ -1511,9 +1471,9 @@ Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer) * (can be NULL -- that's not an error) */ static void * -Peers_handle_inbound_channel (void *cls, - struct GNUNET_CADET_Channel *channel, - const struct GNUNET_PeerIdentity *initiator) +handle_inbound_channel (void *cls, + struct GNUNET_CADET_Channel *channel, + const struct GNUNET_PeerIdentity *initiator) { struct PeerContext *peer_ctx; struct GNUNET_PeerIdentity *ctx_peer; @@ -1531,14 +1491,12 @@ Peers_handle_inbound_channel (void *cls, channel_ctx = add_channel_ctx (peer_ctx); channel_ctx->channel = channel; /* We only accept one incoming channel per peer */ - if (GNUNET_YES == Peers_check_peer_send_intention (initiator)) + if (GNUNET_YES == check_peer_send_intention (initiator)) { LOG (GNUNET_ERROR_TYPE_WARNING, "Already got one receive channel. Destroying old one.\n"); GNUNET_break_op (0); - GNUNET_CADET_channel_destroy (peer_ctx->recv_channel_ctx->channel); - peer_ctx->recv_channel_ctx->channel = NULL; - remove_channel_ctx (peer_ctx->recv_channel_ctx); + destroy_channel (peer_ctx->recv_channel_ctx); peer_ctx->recv_channel_ctx = channel_ctx; /* return the channel context */ return channel_ctx; @@ -1557,11 +1515,11 @@ Peers_handle_inbound_channel (void *cls, * #GNUNET_NO otherwise */ static int -Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer) +check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer) { struct PeerContext *peer_ctx; - if (GNUNET_NO == Peers_check_peer_known (peer)) + if (GNUNET_NO == check_peer_known (peer)) { /* If no such peer exists, there is no channel */ return GNUNET_NO; } @@ -1574,46 +1532,6 @@ Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer) } -/** - * @brief check whether the given channel is the sending channel of the given - * peer - * - * @param peer the peer in question - * @param channel the channel to check for - * @param role either #Peers_CHANNEL_ROLE_SENDING, or - * #Peers_CHANNEL_ROLE_RECEIVING - * - * @return #GNUNET_YES if the given chennel is the sending channel of the peer - * #GNUNET_NO otherwise - */ -static int -Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_CADET_Channel *channel, - enum Peers_ChannelRole role) -{ - const struct PeerContext *peer_ctx; - - if (GNUNET_NO == Peers_check_peer_known (peer)) - { - return GNUNET_NO; - } - peer_ctx = get_peer_ctx (peer); - if ( (Peers_CHANNEL_ROLE_SENDING == role) && - (NULL != peer_ctx->send_channel_ctx) && - (channel == peer_ctx->send_channel_ctx->channel) ) - { - return GNUNET_YES; - } - if ( (Peers_CHANNEL_ROLE_RECEIVING == role) && - (NULL != peer_ctx->recv_channel_ctx) && - (channel == peer_ctx->recv_channel_ctx->channel) ) - { - return GNUNET_YES; - } - return GNUNET_NO; -} - - /** * @brief Destroy the send channel of a peer e.g. stop indicating a sending * intention to another peer @@ -1627,11 +1545,11 @@ Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer, * #GNUNET_NO otherwise */ static int -Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer) +destroy_sending_channel (const struct GNUNET_PeerIdentity *peer) { struct PeerContext *peer_ctx; - if (GNUNET_NO == Peers_check_peer_known (peer)) + if (GNUNET_NO == check_peer_known (peer)) { return GNUNET_NO; } @@ -1639,7 +1557,7 @@ Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer) if (NULL != peer_ctx->send_channel_ctx) { destroy_channel (peer_ctx->send_channel_ctx); - (void) Peers_check_connected (peer); + (void) check_connected (peer); return GNUNET_YES; } return GNUNET_NO; @@ -1656,9 +1574,9 @@ Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer) * @param type type of the message */ static void -Peers_send_message (const struct GNUNET_PeerIdentity *peer, - struct GNUNET_MQ_Envelope *ev, - const char *type) +send_message (const struct GNUNET_PeerIdentity *peer, + struct GNUNET_MQ_Envelope *ev, + const char *type) { struct PendingMessage *pending_msg; struct GNUNET_MQ_Handle *mq; @@ -1686,13 +1604,13 @@ Peers_send_message (const struct GNUNET_PeerIdentity *peer, * #GNUNET_NO otherwise */ static int -Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer, +schedule_operation (const struct GNUNET_PeerIdentity *peer, const PeerOp peer_op) { struct PeerPendingOp pending_op; struct PeerContext *peer_ctx; - GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer)); + GNUNET_assert (GNUNET_YES == check_peer_known (peer)); //TODO if LIVE/ONLINE execute immediately @@ -1709,24 +1627,6 @@ Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer, return GNUNET_NO; } -/** - * @brief Get the recv_channel of @a peer. - * Needed to correctly handle (call #GNUNET_CADET_receive_done()) incoming - * messages. - * - * @param peer The peer to get the recv_channel from. - * - * @return The recv_channel. - */ -static struct GNUNET_CADET_Channel * -Peers_get_recv_channel (const struct GNUNET_PeerIdentity *peer) -{ - struct PeerContext *peer_ctx; - - GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer)); - peer_ctx = get_peer_ctx (peer); - return peer_ctx->recv_channel_ctx->channel; -} /*********************************************************************** * /Old gnunet-service-rps_peers.c ***********************************************************************/ @@ -2182,16 +2082,16 @@ insert_in_view (const struct GNUNET_PeerIdentity *peer) { int online; - online = Peers_check_peer_flag (peer, Peers_ONLINE); + online = check_peer_flag (peer, Peers_ONLINE); if ( (GNUNET_NO == online) || (GNUNET_SYSERR == online) ) /* peer is not even known */ { - (void) Peers_issue_peer_liveliness_check (peer); - (void) Peers_schedule_operation (peer, insert_in_view_op); + (void) issue_peer_liveliness_check (peer); + (void) schedule_operation (peer, insert_in_view_op); return GNUNET_NO; } /* Open channel towards peer to keep connection open */ - Peers_indicate_sending_intention (peer); + indicate_sending_intention (peer); return View_put (peer); } @@ -2384,7 +2284,7 @@ send_pull_reply (const struct GNUNET_PeerIdentity *peer_id, GNUNET_memcpy (&out_msg[1], peer_ids, send_size * sizeof (struct GNUNET_PeerIdentity)); - Peers_send_message (peer_id, ev, "PULL REPLY"); + send_message (peer_id, ev, "PULL REPLY"); GNUNET_STATISTICS_update(stats, "# pull reply send issued", 1, GNUNET_NO); // TODO check with send intention: as send_channel is used/opened we indicate // a sending intention without intending it. @@ -2435,10 +2335,10 @@ insert_in_sampler (void *cls, if (0 < RPS_sampler_count_id (prot_sampler, peer)) { /* Make sure we 'know' about this peer */ - (void) Peers_issue_peer_liveliness_check (peer); + (void) issue_peer_liveliness_check (peer); /* Establish a channel towards that peer to indicate we are going to send * messages to it */ - //Peers_indicate_sending_intention (peer); + //indicate_sending_intention (peer); } #ifdef TO_FILE num_observed_peers++; @@ -2470,10 +2370,10 @@ static void got_peer (const struct GNUNET_PeerIdentity *peer) { /* If we did not know this peer already, insert it into sampler and view */ - if (GNUNET_YES == Peers_issue_peer_liveliness_check (peer)) + if (GNUNET_YES == issue_peer_liveliness_check (peer)) { - Peers_schedule_operation (peer, insert_in_sampler); - Peers_schedule_operation (peer, insert_in_view_op); + schedule_operation (peer, insert_in_sampler); + schedule_operation (peer, insert_in_view_op); } } @@ -2488,17 +2388,17 @@ static int check_sending_channel_needed (const struct GNUNET_PeerIdentity *peer) { /* struct GNUNET_CADET_Channel *channel; */ - if (GNUNET_NO == Peers_check_peer_known (peer)) + if (GNUNET_NO == check_peer_known (peer)) { return GNUNET_NO; } - if (GNUNET_YES == Peers_check_sending_channel_exists (peer)) + if (GNUNET_YES == check_sending_channel_exists (peer)) { if ( (0 < RPS_sampler_count_id (prot_sampler, peer)) || (GNUNET_YES == View_contains_peer (peer)) || (GNUNET_YES == CustomPeerMap_contains_peer (push_map, peer)) || (GNUNET_YES == CustomPeerMap_contains_peer (pull_map, peer)) || - (GNUNET_YES == Peers_check_peer_flag (peer, Peers_PULL_REPLY_PENDING))) + (GNUNET_YES == check_peer_flag (peer, Peers_PULL_REPLY_PENDING))) { /* If we want to keep the connection to peer open */ return GNUNET_YES; } @@ -2542,19 +2442,19 @@ clean_peer (const struct GNUNET_PeerIdentity *peer) GNUNET_i2s (peer)); #ifdef ENABLE_MALICIOUS if (0 != GNUNET_CRYPTO_cmp_peer_identity (&attacked_peer, peer)) - (void) Peers_destroy_sending_channel (peer); + (void) destroy_sending_channel (peer); #else /* ENABLE_MALICIOUS */ - (void) Peers_destroy_sending_channel (peer); + (void) destroy_sending_channel (peer); #endif /* ENABLE_MALICIOUS */ } - if ( (GNUNET_NO == Peers_check_peer_send_intention (peer)) && + if ( (GNUNET_NO == check_peer_send_intention (peer)) && (GNUNET_NO == View_contains_peer (peer)) && (GNUNET_NO == CustomPeerMap_contains_peer (push_map, peer)) && (GNUNET_NO == CustomPeerMap_contains_peer (push_map, peer)) && (0 == RPS_sampler_count_id (prot_sampler, peer)) && (0 == RPS_sampler_count_id (client_sampler, peer)) && - (GNUNET_NO != Peers_check_removable (peer)) ) + (GNUNET_NO != check_removable (peer)) ) { /* We can safely remove this peer */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Going to remove peer %s\n", @@ -2564,49 +2464,6 @@ clean_peer (const struct GNUNET_PeerIdentity *peer) } } -/** - * @brief Allocate memory for a new channel context and insert it into DLL - * - * @param peer_ctx context of the according peer - * - * @return The channel context - */ -static struct ChannelCtx * -add_channel_ctx (struct PeerContext *peer_ctx) -{ - struct ChannelCtx *channel_ctx; - channel_ctx = GNUNET_new (struct ChannelCtx); - channel_ctx->peer_ctx = peer_ctx; - return channel_ctx; -} - - -/** - * @brief Remove the channel context from the DLL and free the memory. - * - * @param channel_ctx The channel context. - */ -static void -remove_channel_ctx (struct ChannelCtx *channel_ctx) -{ - struct PeerContext *peer_ctx = channel_ctx->peer_ctx; - - GNUNET_free (channel_ctx); - if (channel_ctx == peer_ctx->send_channel_ctx) - { - peer_ctx->send_channel_ctx = NULL; - peer_ctx->mq = NULL; - } - else if (channel_ctx == peer_ctx->recv_channel_ctx) - { - peer_ctx->recv_channel_ctx = NULL; - } - else - { - GNUNET_assert (0); - } -} - /** * @brief This is called when a channel is destroyed. @@ -3096,7 +2953,7 @@ handle_peer_push (void *cls, /* Add the sending peer to the push_map */ CustomPeerMap_put (push_map, peer); - GNUNET_break_op (Peers_check_peer_known (peer)); + GNUNET_break_op (check_peer_known (peer)); GNUNET_CADET_receive_done (channel_ctx->channel); } @@ -3136,7 +2993,7 @@ handle_peer_pull_request (void *cls, } #endif /* ENABLE_MALICIOUS */ - GNUNET_break_op (Peers_check_peer_known (peer)); + GNUNET_break_op (check_peer_known (peer)); GNUNET_CADET_receive_done (channel_ctx->channel); view_array = View_get_as_array (); send_pull_reply (peer, view_array, View_size ()); @@ -3174,7 +3031,7 @@ check_peer_pull_reply (void *cls, return GNUNET_SYSERR; } - if (GNUNET_YES != Peers_check_peer_flag (sender, Peers_PULL_REPLY_PENDING)) + if (GNUNET_YES != check_peer_flag (sender, Peers_PULL_REPLY_PENDING)) { LOG (GNUNET_ERROR_TYPE_WARNING, "Received a pull reply from a peer (%s) we didn't request one from!\n", @@ -3248,23 +3105,23 @@ handle_peer_pull_reply (void *cls, } #endif /* ENABLE_MALICIOUS */ /* Make sure we 'know' about this peer */ - (void) Peers_insert_peer (&peers[i]); + (void) insert_peer (&peers[i]); - if (GNUNET_YES == Peers_check_peer_valid (&peers[i])) + if (GNUNET_YES == check_peer_valid (&peers[i])) { CustomPeerMap_put (pull_map, &peers[i]); } else { - Peers_schedule_operation (&peers[i], insert_in_pull_map); - (void) Peers_issue_peer_liveliness_check (&peers[i]); + schedule_operation (&peers[i], insert_in_pull_map); + (void) issue_peer_liveliness_check (&peers[i]); } } - Peers_unset_peer_flag (sender, Peers_PULL_REPLY_PENDING); + UNSET_PEER_FLAG (get_peer_ctx (sender), Peers_PULL_REPLY_PENDING); clean_peer (sender); - GNUNET_break_op (Peers_check_peer_known (sender)); + GNUNET_break_op (check_peer_known (sender)); GNUNET_CADET_receive_done (channel_ctx->channel); } @@ -3328,16 +3185,16 @@ send_pull_request (const struct GNUNET_PeerIdentity *peer) { struct GNUNET_MQ_Envelope *ev; - GNUNET_assert (GNUNET_NO == Peers_check_peer_flag (peer, + GNUNET_assert (GNUNET_NO == check_peer_flag (peer, Peers_PULL_REPLY_PENDING)); - Peers_set_peer_flag (peer, Peers_PULL_REPLY_PENDING); + SET_PEER_FLAG (get_peer_ctx (peer), Peers_PULL_REPLY_PENDING); LOG (GNUNET_ERROR_TYPE_DEBUG, "Going to send PULL REQUEST to peer %s.\n", GNUNET_i2s (peer)); ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST); - Peers_send_message (peer, ev, "PULL REQUEST"); + send_message (peer, ev, "PULL REQUEST"); GNUNET_STATISTICS_update(stats, "# pull request send issued", 1, GNUNET_NO); } @@ -3357,7 +3214,7 @@ send_push (const struct GNUNET_PeerIdentity *peer_id) GNUNET_i2s (peer_id)); ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_RPS_PP_PUSH); - Peers_send_message (peer_id, ev, "PUSH"); + send_message (peer_id, ev, "PUSH"); GNUNET_STATISTICS_update(stats, "# push send issued", 1, GNUNET_NO); } @@ -3481,9 +3338,9 @@ handle_client_act_malicious (void *cls, &msg->attacked_peer, sizeof (struct GNUNET_PeerIdentity)); /* Set the flag of the attacked peer to valid to avoid problems */ - if (GNUNET_NO == Peers_check_peer_known (&attacked_peer)) + if (GNUNET_NO == check_peer_known (&attacked_peer)) { - (void) Peers_issue_peer_liveliness_check (&attacked_peer); + (void) issue_peer_liveliness_check (&attacked_peer); } LOG (GNUNET_ERROR_TYPE_DEBUG, @@ -3573,8 +3430,8 @@ do_mal_round (void *cls) * Send as many pushes to the attacked peer as possible * That is one push per round as it will ignore more. */ - (void) Peers_issue_peer_liveliness_check (&attacked_peer); - if (GNUNET_YES == Peers_check_peer_flag (&attacked_peer, Peers_ONLINE)) + (void) issue_peer_liveliness_check (&attacked_peer); + if (GNUNET_YES == check_peer_flag (&attacked_peer, Peers_ONLINE)) send_push (&attacked_peer); } @@ -3583,10 +3440,10 @@ do_mal_round (void *cls) { /* Combined attack */ /* Send PUSH to attacked peers */ - if (GNUNET_YES == Peers_check_peer_known (&attacked_peer)) + if (GNUNET_YES == check_peer_known (&attacked_peer)) { - (void) Peers_issue_peer_liveliness_check (&attacked_peer); - if (GNUNET_YES == Peers_check_peer_flag (&attacked_peer, Peers_ONLINE)) + (void) issue_peer_liveliness_check (&attacked_peer); + if (GNUNET_YES == check_peer_flag (&attacked_peer, Peers_ONLINE)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Goding to send push to attacked peer (%s)\n", @@ -3594,7 +3451,7 @@ do_mal_round (void *cls) send_push (&attacked_peer); } } - (void) Peers_issue_peer_liveliness_check (&attacked_peer); + (void) issue_peer_liveliness_check (&attacked_peer); /* The maximum of pushes we're going to send this round */ num_pushes = GNUNET_MIN (GNUNET_MIN (push_limit - 1, @@ -3711,7 +3568,7 @@ do_round (void *cls) for (i = first_border; i < second_border; i++) { peer = view_array[permut[i]]; - if ( GNUNET_NO == Peers_check_peer_flag (&peer, Peers_PULL_REPLY_PENDING)) + if ( GNUNET_NO == check_peer_flag (&peer, Peers_PULL_REPLY_PENDING)) { // FIXME if this fails schedule/loop this for later send_pull_request (&peer); } @@ -4227,7 +4084,7 @@ run (void *cls, &port); cadet_port = GNUNET_CADET_open_port (cadet_handle, &port, - &Peers_handle_inbound_channel, /* Connect handler */ + &handle_inbound_channel, /* Connect handler */ NULL, /* cls */ NULL, /* WindowSize handler */ &cleanup_destroyed_channel, /* Disconnect handler */ @@ -4242,7 +4099,7 @@ run (void *cls, peerinfo_handle = GNUNET_PEERINFO_connect (cfg); - Peers_initialise (fn_valid_peers, cadet_handle); + initialise_peers (fn_valid_peers, cadet_handle); GNUNET_free (fn_valid_peers); /* Initialise sampler */ @@ -4265,7 +4122,7 @@ run (void *cls, // TODO send push/pull to each of those peers? // TODO read stored valid peers from last run LOG (GNUNET_ERROR_TYPE_DEBUG, "Requesting stored valid peers\n"); - Peers_get_valid_peers (valid_peers_iterator, NULL); + get_valid_peers (valid_peers_iterator, NULL); peerinfo_notify_handle = GNUNET_PEERINFO_notify (cfg, GNUNET_NO, -- cgit v1.2.3 From 3318097204119e550a5e9691d7c3f11ea64fc8a8 Mon Sep 17 00:00:00 2001 From: Julius Bünger Date: Mon, 13 Aug 2018 17:32:58 +0200 Subject: Schedule destruction of channel during destruction of other channel --- src/rps/gnunet-service-rps.c | 55 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/rps/gnunet-service-rps.c b/src/rps/gnunet-service-rps.c index 18b9b792b..e0301af6b 100644 --- a/src/rps/gnunet-service-rps.c +++ b/src/rps/gnunet-service-rps.c @@ -275,6 +275,13 @@ struct ChannelCtx * @brief The peer context associated with the channel */ struct PeerContext *peer_ctx; + + /** + * @brief When channel destruction needs to be delayed (because it is called + * from within the cadet routine of another channel destruction) this task + * refers to the respective _SCHEDULER_Task. + */ + struct GNUNET_SCHEDULER_Task *destruction_task; }; /** @@ -304,7 +311,6 @@ static struct GNUNET_CONTAINER_MultiPeerMap *peer_map; static struct GNUNET_CADET_Handle *cadet_handle; - /** * @brief Get the #PeerContext associated with a peer * @@ -864,13 +870,47 @@ destroy_channel (struct ChannelCtx *channel_ctx) { struct PeerContext *peer_ctx = channel_ctx->peer_ctx; - GNUNET_assert (channel_ctx == peer_ctx->send_channel_ctx || - channel_ctx == peer_ctx->recv_channel_ctx); - + if (NULL != channel_ctx->destruction_task) + { + GNUNET_SCHEDULER_cancel (channel_ctx->destruction_task); + channel_ctx->destruction_task = NULL; + } GNUNET_CADET_channel_destroy (channel_ctx->channel); + channel_ctx->channel = NULL; remove_channel_ctx (channel_ctx); } +/** + * @brief Destroy a cadet channel. + * + * This satisfies the function signature of #GNUNET_SCHEDULER_TaskCallback. + * + * @param cls + */ +static void +destroy_channel_cb (void *cls) +{ + struct ChannelCtx *channel_ctx = cls; + channel_ctx->destruction_task = NULL; + destroy_channel (channel_ctx); +} + +/** + * @brief Schedule the destruction of a channel for immediately afterwards. + * + * In case a channel is to be destroyed from within the callback to the + * destruction of another channel (send channel), we cannot call + * GNUNET_CADET_channel_destroy directly, but need to use this scheduling + * construction. + * + * @param channel_ctx channel to be destroyed. + */ +static void +schedule_channel_destruction (struct ChannelCtx *channel_ctx) +{ + channel_ctx->destruction_task = + GNUNET_SCHEDULER_add_now (destroy_channel_cb, channel_ctx); +} /** * @brief Remove peer @@ -937,11 +977,13 @@ destroy_peer (struct PeerContext *peer_ctx) if (NULL != peer_ctx->send_channel_ctx) { - destroy_channel (peer_ctx->send_channel_ctx); + /* This is possibly called from within channel destruction */ + schedule_channel_destruction (peer_ctx->send_channel_ctx); } if (NULL != peer_ctx->recv_channel_ctx) { - destroy_channel (peer_ctx->recv_channel_ctx); + /* This is possibly called from within channel destruction */ + schedule_channel_destruction (peer_ctx->recv_channel_ctx); } if (GNUNET_YES != @@ -3874,6 +3916,7 @@ shutdown_task (void *cls) RPS_sampler_destroy (client_sampler); GNUNET_CADET_close_port (cadet_port); GNUNET_CADET_disconnect (cadet_handle); + cadet_handle = NULL; View_destroy (); CustomPeerMap_destroy (push_map); CustomPeerMap_destroy (pull_map); -- cgit v1.2.3 From b8da8b39b97eb830a7c03c79e5e1d8508026987c Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 13 Aug 2018 17:58:10 +0200 Subject: do notify client about destroyed channel on MQ error --- src/cadet/cadet_api.c | 3 +++ src/cadet/gnunet-service-cadet_hello.c | 7 ++----- src/hostlist/hostlist.conf | 2 ++ src/rps/gnunet-service-rps.c | 22 +++++++++++++++++----- src/rps/test_rps.conf | 1 + 5 files changed, 25 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/cadet/cadet_api.c b/src/cadet/cadet_api.c index e2ca461a5..23ea46e59 100644 --- a/src/cadet/cadet_api.c +++ b/src/cadet/cadet_api.c @@ -549,6 +549,9 @@ cadet_mq_error_handler (void *cls, else { GNUNET_break (0); + if (NULL != ch->disconnects) + ch->disconnects (ch->ctx, + ch); GNUNET_CADET_channel_destroy (ch); } } diff --git a/src/cadet/gnunet-service-cadet_hello.c b/src/cadet/gnunet-service-cadet_hello.c index 61686e5da..0061bddc2 100644 --- a/src/cadet/gnunet-service-cadet_hello.c +++ b/src/cadet/gnunet-service-cadet_hello.c @@ -17,13 +17,10 @@ */ /** * @file cadet/gnunet-service-cadet_hello.c - * @brief spread knowledge about how to contact other peers from PEERINFO + * @brief spread knowledge about how to contact us (get HELLO from peerinfo), + * and remember HELLOs of other peers we have an interest in * @author Bartlomiej Polot * @author Christian Grothoff - * - * TODO: - * - is most of this necessary/helpful? - * - should we not simply restrict this to OUR hello? */ #include "platform.h" #include "gnunet_util_lib.h" diff --git a/src/hostlist/hostlist.conf b/src/hostlist/hostlist.conf index 59cc351cc..32e5d8320 100644 --- a/src/hostlist/hostlist.conf +++ b/src/hostlist/hostlist.conf @@ -41,3 +41,5 @@ SERVERS = http://v10.gnunet.org/hostlist https://gnunet.io/hostlist # Valid values: HTTP, HTTP_1_0, SOCKS4, SOCKS5, SOCKS4A, SOCKS5_HOSTNAME # Default: HTTP # PROXY_TYPE = HTTP + + diff --git a/src/rps/gnunet-service-rps.c b/src/rps/gnunet-service-rps.c index e0301af6b..41769ca24 100644 --- a/src/rps/gnunet-service-rps.c +++ b/src/rps/gnunet-service-rps.c @@ -701,7 +701,7 @@ get_channel (const struct GNUNET_PeerIdentity *peer) &port, GNUNET_CADET_OPTION_RELIABLE, NULL, /* WindowSize handler */ - cleanup_destroyed_channel, /* Disconnect handler */ + &cleanup_destroyed_channel, /* Disconnect handler */ cadet_handlers); } GNUNET_assert (NULL != peer_ctx->send_channel_ctx); @@ -860,6 +860,7 @@ check_operation_scheduled (const struct GNUNET_PeerIdentity *peer, return GNUNET_NO; } + /** * @brief Callback for scheduler to destroy a channel * @@ -869,17 +870,20 @@ static void destroy_channel (struct ChannelCtx *channel_ctx) { struct PeerContext *peer_ctx = channel_ctx->peer_ctx; - + struct GNUNET_CADET_Channel *channel; + if (NULL != channel_ctx->destruction_task) { GNUNET_SCHEDULER_cancel (channel_ctx->destruction_task); channel_ctx->destruction_task = NULL; } - GNUNET_CADET_channel_destroy (channel_ctx->channel); + channel = channel_ctx->channel; channel_ctx->channel = NULL; + GNUNET_CADET_channel_destroy (channel); remove_channel_ctx (channel_ctx); } + /** * @brief Destroy a cadet channel. * @@ -891,10 +895,12 @@ static void destroy_channel_cb (void *cls) { struct ChannelCtx *channel_ctx = cls; + channel_ctx->destruction_task = NULL; destroy_channel (channel_ctx); } + /** * @brief Schedule the destruction of a channel for immediately afterwards. * @@ -908,10 +914,16 @@ destroy_channel_cb (void *cls) static void schedule_channel_destruction (struct ChannelCtx *channel_ctx) { + GNUNET_assert (NULL == + channel_ctx->destruction_task); + GNUNET_assert (NULL != + channel_ctx->channel); channel_ctx->destruction_task = - GNUNET_SCHEDULER_add_now (destroy_channel_cb, channel_ctx); + GNUNET_SCHEDULER_add_now (&destroy_channel_cb, + channel_ctx); } + /** * @brief Remove peer * @@ -2530,7 +2542,7 @@ cleanup_destroyed_channel (void *cls, // * cleanup everything related to the channel // * memory // * remove peer if necessary - + channel_ctx->channel = NULL; if (peer_ctx->recv_channel_ctx == channel_ctx) { remove_channel_ctx (channel_ctx); diff --git a/src/rps/test_rps.conf b/src/rps/test_rps.conf index 02fbf76a4..e751dafbc 100644 --- a/src/rps/test_rps.conf +++ b/src/rps/test_rps.conf @@ -1,6 +1,7 @@ [rps] #PREFIX = valgrind --leak-check=full --show-leak-kinds=all --log-file=/tmp/rps/valgrind!gnunet-service-rps!%p #PREFIX = valgrind --log-file=/tmp/rps/valgrind!gnunet-service-rps!%p +#PREFIX = valgrind #BINARY = gnunet-service-rps UNIXPATH = $GNUNET_TMP/gnunet-service-rps.sock HOME = $SERVICEHOME -- cgit v1.2.3 From 975ae6b7f7f6943ffba6f239187b770d8c10a7da Mon Sep 17 00:00:00 2001 From: Julius Bünger Date: Mon, 13 Aug 2018 18:11:35 +0200 Subject: Add BINARY to test config --- src/rps/test_rps.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/rps/test_rps.conf b/src/rps/test_rps.conf index e751dafbc..214da8578 100644 --- a/src/rps/test_rps.conf +++ b/src/rps/test_rps.conf @@ -2,7 +2,7 @@ #PREFIX = valgrind --leak-check=full --show-leak-kinds=all --log-file=/tmp/rps/valgrind!gnunet-service-rps!%p #PREFIX = valgrind --log-file=/tmp/rps/valgrind!gnunet-service-rps!%p #PREFIX = valgrind -#BINARY = gnunet-service-rps +BINARY = gnunet-service-rps UNIXPATH = $GNUNET_TMP/gnunet-service-rps.sock HOME = $SERVICEHOME # PORT = 2106 -- cgit v1.2.3 From b3e39566bfdda23522a468a93267bc97bf8e6491 Mon Sep 17 00:00:00 2001 From: Julius Bünger Date: Mon, 13 Aug 2018 18:13:35 +0200 Subject: Remove BINARY from test configuration --- src/rps/test_rps.conf | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/rps/test_rps.conf b/src/rps/test_rps.conf index 214da8578..84e0e5049 100644 --- a/src/rps/test_rps.conf +++ b/src/rps/test_rps.conf @@ -2,7 +2,6 @@ #PREFIX = valgrind --leak-check=full --show-leak-kinds=all --log-file=/tmp/rps/valgrind!gnunet-service-rps!%p #PREFIX = valgrind --log-file=/tmp/rps/valgrind!gnunet-service-rps!%p #PREFIX = valgrind -BINARY = gnunet-service-rps UNIXPATH = $GNUNET_TMP/gnunet-service-rps.sock HOME = $SERVICEHOME # PORT = 2106 -- cgit v1.2.3 From b67807b3e8f732054506fb4e229e392013ece923 Mon Sep 17 00:00:00 2001 From: Julius Bünger Date: Mon, 13 Aug 2018 19:08:02 +0200 Subject: Fix documentation and assertions --- src/rps/gnunet-service-rps.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/rps/gnunet-service-rps.c b/src/rps/gnunet-service-rps.c index 41769ca24..1f155b14f 100644 --- a/src/rps/gnunet-service-rps.c +++ b/src/rps/gnunet-service-rps.c @@ -625,7 +625,7 @@ add_channel_ctx (struct PeerContext *peer_ctx) /** - * @brief Remove the channel context from the DLL and free the memory. + * @brief Free memory and NULL pointers. * * @param channel_ctx The channel context. */ @@ -645,10 +645,6 @@ remove_channel_ctx (struct ChannelCtx *channel_ctx) GNUNET_free (channel_ctx); peer_ctx->recv_channel_ctx = NULL; } - else - { - GNUNET_assert (0); - } } @@ -869,14 +865,14 @@ check_operation_scheduled (const struct GNUNET_PeerIdentity *peer, static void destroy_channel (struct ChannelCtx *channel_ctx) { - struct PeerContext *peer_ctx = channel_ctx->peer_ctx; struct GNUNET_CADET_Channel *channel; - + if (NULL != channel_ctx->destruction_task) { GNUNET_SCHEDULER_cancel (channel_ctx->destruction_task); channel_ctx->destruction_task = NULL; } + GNUNET_assert (channel_ctx->channel != NULL); channel = channel_ctx->channel; channel_ctx->channel = NULL; GNUNET_CADET_channel_destroy (channel); -- cgit v1.2.3 From 4cc09ba10da89ac32b4a40bde9abbe77bba21c78 Mon Sep 17 00:00:00 2001 From: Phil Date: Tue, 14 Aug 2018 01:05:18 +0200 Subject: fixed makefile for plugin_rest_gns, json_generator --- src/json/json_generator.c | 2 +- src/rest-plugins/Makefile.am | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/json/json_generator.c b/src/json/json_generator.c index 0ffe5c643..96f07bdc2 100644 --- a/src/json/json_generator.c +++ b/src/json/json_generator.c @@ -193,7 +193,7 @@ GNUNET_JSON_from_gns_record (const char* rname, expiration_time_str, "flag", flags, - "label", + "record_name", rname); } else diff --git a/src/rest-plugins/Makefile.am b/src/rest-plugins/Makefile.am index 3acf8839e..486692b72 100644 --- a/src/rest-plugins/Makefile.am +++ b/src/rest-plugins/Makefile.am @@ -80,6 +80,7 @@ libgnunet_plugin_rest_gns_la_LIBADD = \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/rest/libgnunetrest.la \ $(top_builddir)/src/identity/libgnunetidentity.la \ + $(top_builddir)/src/json/libgnunetjson.la \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ $(LTLIBINTL) -ljansson -lmicrohttpd libgnunet_plugin_rest_gns_la_LDFLAGS = \ -- cgit v1.2.3