12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442 |
- /*
- 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 <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: AGPL3.0-or-later
- */
- /**
- * @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 <jansson.h>
- /**
- * Identity Namespace
- */
- #define GNUNET_REST_API_NS_IDENTITY "/identity"
- /**
- * 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 private key
- */
- #define GNUNET_REST_IDENTITY_PARAM_PRIVKEY "privkey"
- /**
- * 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;
- /**
- * Ego list
- */
- static struct EgoEntry *ego_head;
- /**
- * Ego list
- */
- static struct EgoEntry *ego_tail;
- /**
- * The processing state
- */
- static int state;
- /**
- * Handle to Identity service.
- */
- static struct GNUNET_IDENTITY_Handle *identity_handle;
- /**
- * @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
- {
- /**
- * DLL
- */
- struct RequestHandle *next;
- /**
- * DLL
- */
- struct RequestHandle *prev;
- /**
- * 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;
- /**
- * 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;
- };
- /**
- * DLL
- */
- static struct RequestHandle *requests_head;
- /**
- * DLL
- */
- static struct RequestHandle *requests_tail;
- /**
- * 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->name)
- GNUNET_free (handle->name);
- GNUNET_CONTAINER_DLL_remove (requests_head,
- requests_tail,
- handle);
- 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);
- GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
- "Content-Type",
- "application/json"));
- 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 = 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 = 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_IDENTITY_PublicKey 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_IDENTITY_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);
- GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
- "Content-Type",
- "application/json"));
- 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 (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;
- struct GNUNET_HashCode key;
- json_t *json_root;
- json_t *json_ego;
- char *result_str;
- char *privkey_str;
- json_root = json_array ();
- // Return ego/egos
- for (ego_entry = 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));
- GNUNET_CRYPTO_hash ("private", strlen ("private"), &key);
- if (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (
- handle->rest_handle->url_param_map, &key))
- {
- privkey_str = GNUNET_IDENTITY_private_key_to_string (
- GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego));
- json_object_set_new (json_ego,
- GNUNET_REST_IDENTITY_PARAM_PRIVKEY,
- json_string (privkey_str));
- GNUNET_free (privkey_str);
- }
- 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);
- }
- 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);
- GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
- "Content-Type",
- "application/json"));
- 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;
- struct GNUNET_HashCode key;
- json_t *json_ego;
- char *result_str;
- char *privkey_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));
- GNUNET_CRYPTO_hash ("private", strlen ("private"), &key);
- if (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (
- handle->rest_handle->url_param_map, &key))
- {
- privkey_str = GNUNET_IDENTITY_private_key_to_string (
- GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego));
- json_object_set_new (json_ego,
- GNUNET_REST_IDENTITY_PARAM_PRIVKEY,
- json_string (privkey_str));
- GNUNET_free (privkey_str);
- }
- 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);
- GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
- "Content-Type",
- "application/json"));
- 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 finished, when creating an ego.
- *
- * @param cls request handle
- * @param private key of the ego, or NULL on error
- * @param emsg error message
- */
- static void
- do_finished_create (void *cls,
- const struct GNUNET_IDENTITY_PrivateKey *pk,
- const char *emsg)
- {
- struct RequestHandle *handle = cls;
- (void) pk;
- do_finished (handle, emsg);
- }
- /**
- * 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 (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 (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;
- char *privkey;
- struct GNUNET_IDENTITY_PrivateKey pk;
- struct GNUNET_IDENTITY_PrivateKey *pk_ptr;
- 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;
- privkey = NULL;
- json_unpack_state =
- json_unpack (data_js, "{s:s, s?:s!}",
- GNUNET_REST_IDENTITY_PARAM_NAME, &egoname,
- GNUNET_REST_IDENTITY_PARAM_PRIVKEY, &privkey);
- 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 = 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);
- if (NULL != privkey)
- {
- GNUNET_STRINGS_string_to_data (privkey,
- strlen (privkey),
- &pk,
- sizeof(struct
- GNUNET_IDENTITY_PrivateKey));
- pk_ptr = &pk;
- }
- else
- pk_ptr = NULL;
- json_decref (data_js);
- handle->response_code = MHD_HTTP_CREATED;
- handle->op = GNUNET_IDENTITY_create (identity_handle,
- handle->name,
- pk_ptr,
- GNUNET_IDENTITY_TYPE_ECDSA,
- &do_finished_create,
- 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 (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 (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);
- GNUNET_assert (MHD_NO != 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;
- }
- static void
- list_ego (void *cls,
- struct GNUNET_IDENTITY_Ego *ego,
- void **ctx,
- const char *identifier)
- {
- struct EgoEntry *ego_entry;
- struct GNUNET_IDENTITY_PublicKey pk;
- if ((NULL == ego) && (ID_REST_STATE_INIT == state))
- {
- state = ID_REST_STATE_POST_INIT;
- return;
- }
- if (NULL == ego)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Called with NULL ego\n");
- return;
- }
- if (ID_REST_STATE_INIT == state)
- {
- ego_entry = GNUNET_new (struct EgoEntry);
- GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
- ego_entry->keystring = GNUNET_IDENTITY_public_key_to_string (&pk);
- ego_entry->ego = ego;
- ego_entry->identifier = GNUNET_strdup (identifier);
- GNUNET_CONTAINER_DLL_insert_tail (ego_head,
- ego_tail,
- ego_entry);
- }
- /* Ego renamed or added */
- if (identifier != NULL)
- {
- for (ego_entry = 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_IDENTITY_public_key_to_string (&pk);
- ego_entry->ego = ego;
- ego_entry->identifier = GNUNET_strdup (identifier);
- GNUNET_CONTAINER_DLL_insert_tail (ego_head,
- ego_tail,
- ego_entry);
- }
- }
- else
- {
- /* Delete */
- for (ego_entry = ego_head; NULL != ego_entry;
- ego_entry = ego_entry->next)
- {
- if (ego_entry->ego == ego)
- break;
- }
- if (NULL == ego_entry)
- return; /* Not found */
- GNUNET_CONTAINER_DLL_remove (ego_head,
- ego_tail,
- ego_entry);
- GNUNET_free (ego_entry->identifier);
- GNUNET_free (ego_entry->keystring);
- GNUNET_free (ego_entry);
- return;
- }
- }
- /**
- * 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 enum GNUNET_GenericReturnValue
- rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
- GNUNET_REST_ResultProcessor proc,
- void *proc_cls)
- {
- struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
- struct GNUNET_REST_RequestHandlerError err;
- static const struct GNUNET_REST_RequestHandler handlers[] =
- { { 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_GET, GNUNET_REST_API_NS_IDENTITY, &ego_get_all },
- { 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 };
- 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';
- handle->timeout_task =
- GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_error, handle);
- GNUNET_CONTAINER_DLL_insert (requests_head,
- requests_tail,
- handle);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
- if (GNUNET_NO ==
- GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
- {
- cleanup_handle (handle);
- return GNUNET_NO;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
- return GNUNET_YES;
- }
- /**
- * 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);
- state = ID_REST_STATE_INIT;
- identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, NULL);
- 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;
- struct EgoEntry *ego_entry;
- struct EgoEntry *ego_tmp;
- plugin->cfg = NULL;
- while (NULL != requests_head)
- cleanup_handle (requests_head);
- if (NULL != identity_handle)
- GNUNET_IDENTITY_disconnect (identity_handle);
- for (ego_entry = 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 (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 */
|