aboutsummaryrefslogtreecommitdiff
path: root/src/rest
diff options
context:
space:
mode:
authorMartin Schanzenbach <mschanzenbach@posteo.de>2015-09-14 11:10:11 +0000
committerMartin Schanzenbach <mschanzenbach@posteo.de>2015-09-14 11:10:11 +0000
commitb0a03eeebfdedbb7b0070ef00514f321aafa49db (patch)
tree06233b8dc0c1bf8ee580367e772c9951a3d7cee6 /src/rest
parent134da182130592c78bdb5d348826825665a2ffab (diff)
downloadgnunet-b0a03eeebfdedbb7b0070ef00514f321aafa49db.tar.gz
gnunet-b0a03eeebfdedbb7b0070ef00514f321aafa49db.zip
- revert plugin move. Add new identity-token
Diffstat (limited to 'src/rest')
-rw-r--r--src/rest/Makefile.am37
-rw-r--r--src/rest/plugin_rest_gns.c720
-rw-r--r--src/rest/plugin_rest_identity.c1080
-rw-r--r--src/rest/plugin_rest_namestore.c1107
4 files changed, 1 insertions, 2943 deletions
diff --git a/src/rest/Makefile.am b/src/rest/Makefile.am
index cd429abc1..9ab7c03e0 100644
--- a/src/rest/Makefile.am
+++ b/src/rest/Makefile.am
@@ -20,13 +20,8 @@ if USE_COVERAGE
20 XLIBS = -lgcov 20 XLIBS = -lgcov
21endif 21endif
22 22
23REST_PLUGINS = libgnunet_plugin_rest_gns.la \
24 libgnunet_plugin_rest_identity.la \
25 libgnunet_plugin_rest_namestore.la
26
27lib_LTLIBRARIES = \ 23lib_LTLIBRARIES = \
28 libgnunetrest.la \ 24 libgnunetrest.la
29 $(REST_PLUGINS)
30 25
31libexec_PROGRAMS = \ 26libexec_PROGRAMS = \
32 gnunet-rest-server 27 gnunet-rest-server
@@ -48,33 +43,3 @@ libgnunetrest_la_LDFLAGS = \
48 $(GN_LIB_LDFLAGS) \ 43 $(GN_LIB_LDFLAGS) \
49 -version-info 0:0:0 44 -version-info 0:0:0
50 45
51libgnunet_plugin_rest_gns_la_SOURCES = \
52 plugin_rest_gns.c
53libgnunet_plugin_rest_gns_la_LIBADD = \
54 $(top_builddir)/src/gns/libgnunetgns.la \
55 $(top_builddir)/src/identity/libgnunetidentity.la \
56 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
57 $(LTLIBINTL) -ljansson -lmicrohttpd
58libgnunet_plugin_rest_gns_la_LDFLAGS = \
59 $(GN_PLUGIN_LDFLAGS)
60
61
62libgnunet_plugin_rest_identity_la_SOURCES = \
63 plugin_rest_namestore.c
64libgnunet_plugin_rest_identity_la_LIBADD = \
65 $(top_builddir)/src/identity/libgnunetidentity.la \
66 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
67 $(LTLIBINTL) -ljansson -lmicrohttpd
68libgnunet_plugin_rest_identity_la_LDFLAGS = \
69 $(GN_PLUGIN_LDFLAGS)
70
71libgnunet_plugin_rest_namestore_la_SOURCES = \
72 plugin_rest_namestore.c
73libgnunet_plugin_rest_namestore_la_LIBADD = \
74 $(top_builddir)/src/namestore/libgnunetnamestore.la \
75 $(top_builddir)/src/identity/libgnunetidentity.la \
76 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
77 $(LTLIBINTL) -ljansson -lmicrohttpd
78libgnunet_plugin_rest_namestore_la_LDFLAGS = \
79 $(GN_PLUGIN_LDFLAGS)
80
diff --git a/src/rest/plugin_rest_gns.c b/src/rest/plugin_rest_gns.c
deleted file mode 100644
index 3ebbfb925..000000000
--- a/src/rest/plugin_rest_gns.c
+++ /dev/null
@@ -1,720 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20/**
21 * @author Martin Schanzenbach
22 * @file gns/plugin_rest_gns.c
23 * @brief GNUnet GNS REST plugin
24 *
25 */
26
27#include "platform.h"
28#include "gnunet_rest_plugin.h"
29#include <gnunet_dnsparser_lib.h>
30#include <gnunet_identity_service.h>
31#include <gnunet_gnsrecord_lib.h>
32#include <gnunet_namestore_service.h>
33#include <gnunet_gns_service.h>
34#include <gnunet_rest_lib.h>
35#include <jansson.h>
36
37#define GNUNET_REST_API_NS_GNS "/gns"
38
39#define GNUNET_REST_JSONAPI_GNS_RECORD_TYPE "record_type"
40
41#define GNUNET_REST_JSONAPI_GNS_TYPEINFO "gns_name"
42
43#define GNUNET_REST_JSONAPI_GNS_RECORD "records"
44
45#define GNUNET_REST_JSONAPI_GNS_EGO "ego"
46
47#define GNUNET_REST_JSONAPI_GNS_PKEY "pkey"
48
49#define GNUNET_REST_JSONAPI_GNS_OPTIONS "options"
50
51/**
52 * @brief struct returned by the initialization function of the plugin
53 */
54struct Plugin
55{
56 const struct GNUNET_CONFIGURATION_Handle *cfg;
57};
58
59const struct GNUNET_CONFIGURATION_Handle *cfg;
60
61struct LookupHandle
62{
63 /**
64 * Handle to GNS service.
65 */
66 struct GNUNET_GNS_Handle *gns;
67
68 /**
69 * Desired timeout for the lookup (default is no timeout).
70 */
71 struct GNUNET_TIME_Relative timeout;
72
73 /**
74 * Handle to lookup request
75 */
76 struct GNUNET_GNS_LookupRequest *lookup_request;
77
78 /**
79 * Lookup an ego with the identity service.
80 */
81 struct GNUNET_IDENTITY_EgoLookup *el;
82
83 /**
84 * Handle for identity service.
85 */
86 struct GNUNET_IDENTITY_Handle *identity;
87
88 /**
89 * Active operation on identity service.
90 */
91 struct GNUNET_IDENTITY_Operation *id_op;
92
93 /**
94 * ID of a task associated with the resolution process.
95 */
96 struct GNUNET_SCHEDULER_Task * timeout_task;
97
98 /**
99 * The root of the received JSON or NULL
100 */
101 json_t *json_root;
102
103 /**
104 * The plugin result processor
105 */
106 GNUNET_REST_ResultProcessor proc;
107
108 /**
109 * The closure of the result processor
110 */
111 void *proc_cls;
112
113 /**
114 * The name to look up
115 */
116 char *name;
117
118 /**
119 * The ego to use
120 * In string representation from JSON
121 */
122 const char *ego_str;
123
124 /**
125 * The Pkey to use
126 * In string representation from JSON
127 */
128 const char *pkey_str;
129
130 /**
131 * The record type
132 */
133 int type;
134
135 /**
136 * The public key of to use for lookup
137 */
138 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
139
140 /**
141 * The public key to use for lookup
142 */
143 struct GNUNET_CRYPTO_EcdsaPublicKey pkeym;
144
145 /**
146 * The resolver options
147 */
148 enum GNUNET_GNS_LocalOptions options;
149
150 /**
151 * the shorten key
152 */
153 struct GNUNET_CRYPTO_EcdsaPrivateKey shorten_key;
154
155};
156
157
158/**
159 * Cleanup lookup handle.
160 *
161 * @param handle Handle to clean up
162 */
163static void
164cleanup_handle (struct LookupHandle *handle)
165{
166 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
167 "Cleaning up\n");
168 if (NULL != handle->json_root)
169 json_decref (handle->json_root);
170
171 if (NULL != handle->name)
172 GNUNET_free (handle->name);
173 if (NULL != handle->el)
174 {
175 GNUNET_IDENTITY_ego_lookup_cancel (handle->el);
176 handle->el = NULL;
177 }
178 if (NULL != handle->id_op)
179 {
180 GNUNET_IDENTITY_cancel (handle->id_op);
181 handle->id_op = NULL;
182 }
183 if (NULL != handle->lookup_request)
184 {
185 GNUNET_GNS_lookup_cancel (handle->lookup_request);
186 handle->lookup_request = NULL;
187 }
188 if (NULL != handle->identity)
189 {
190 GNUNET_IDENTITY_disconnect (handle->identity);
191 handle->identity = NULL;
192 }
193 if (NULL != handle->gns)
194 {
195 GNUNET_GNS_disconnect (handle->gns);
196 handle->gns = NULL;
197 }
198
199 if (NULL != handle->timeout_task)
200 {
201 GNUNET_SCHEDULER_cancel (handle->timeout_task);
202 }
203 GNUNET_free (handle);
204}
205
206
207/**
208 * Task run on shutdown. Cleans up everything.
209 *
210 * @param cls unused
211 * @param tc scheduler context
212 */
213static void
214do_error (void *cls,
215 const struct GNUNET_SCHEDULER_TaskContext *tc)
216{
217 struct LookupHandle *handle = cls;
218 struct MHD_Response *resp = GNUNET_REST_create_json_response (NULL);
219 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
220 cleanup_handle (handle);
221}
222
223
224/**
225 * Create json representation of a GNSRECORD
226 *
227 * @param rd the GNSRECORD_Data
228 */
229static json_t *
230gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
231{
232 const char *typename;
233 char *string_val;
234 const char *exp_str;
235 json_t *record_obj;
236
237 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
238 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
239 rd->data,
240 rd->data_size);
241
242 if (NULL == string_val)
243 {
244 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
245 "Record of type %d malformed, skipping\n",
246 (int) rd->record_type);
247 return NULL;
248 }
249 record_obj = json_object();
250 json_object_set_new (record_obj, "type", json_string (typename));
251 json_object_set_new (record_obj, "value", json_string (string_val));
252 GNUNET_free (string_val);
253
254 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
255 {
256 struct GNUNET_TIME_Relative time_rel;
257 time_rel.rel_value_us = rd->expiration_time;
258 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
259 }
260 else
261 {
262 struct GNUNET_TIME_Absolute time_abs;
263 time_abs.abs_value_us = rd->expiration_time;
264 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
265 }
266 json_object_set_new (record_obj, "expiration_time", json_string (exp_str));
267
268 json_object_set_new (record_obj, "expired",
269 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
270 return record_obj;
271}
272
273/**
274 * Function called with the result of a GNS lookup.
275 *
276 * @param cls the 'const char *' name that was resolved
277 * @param rd_count number of records returned
278 * @param rd array of @a rd_count records with the results
279 */
280static void
281process_lookup_result (void *cls, uint32_t rd_count,
282 const struct GNUNET_GNSRECORD_Data *rd)
283{
284 struct LookupHandle *handle = cls;
285 struct MHD_Response *resp;
286 struct JsonApiObject *json_object;
287 struct JsonApiResource *json_resource;
288 uint32_t i;
289 char *result;
290 json_t *result_array;
291 json_t *record_obj;
292
293 result_array = json_array();
294 json_object = GNUNET_REST_jsonapi_object_new ();
295 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_GNS_TYPEINFO, handle->name);
296 handle->lookup_request = NULL;
297 for (i=0; i<rd_count; i++)
298 {
299 if ( (rd[i].record_type != handle->type) &&
300 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
301 continue;
302 record_obj = gnsrecord_to_json (&(rd[i]));
303 json_array_append (result_array, record_obj);
304 json_decref (record_obj);
305 }
306 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
307 GNUNET_REST_JSONAPI_GNS_RECORD,
308 result_array);
309 GNUNET_REST_jsonapi_object_resource_add (json_object, json_resource);
310 GNUNET_REST_jsonapi_data_serialize (json_object, &result);
311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result);
312 json_decref (result_array);
313 GNUNET_REST_jsonapi_object_delete (json_object);
314 resp = GNUNET_REST_create_json_response (result);
315 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
316 GNUNET_free (result);
317 cleanup_handle (handle);
318}
319
320
321/**
322 * Perform the actual resolution, starting with the zone
323 * identified by the given public key and the shorten zone.
324 *
325 * @param pkey public key to use for the zone, can be NULL
326 * @param shorten_key private key used for shortening, can be NULL
327 */
328static void
329lookup_with_keys (struct LookupHandle *handle, const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_key)
330{
331 if (UINT32_MAX == handle->type)
332 {
333 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
334 _("Invalid typename specified, assuming `ANY'\n"));
335 handle->type = GNUNET_GNSRECORD_TYPE_ANY;
336 }
337 if (NULL != handle->name)
338 {
339 handle->lookup_request = GNUNET_GNS_lookup (handle->gns,
340 handle->name,
341 &handle->pkey,
342 handle->type,
343 handle->options,
344 shorten_key,
345 &process_lookup_result,
346 handle);
347 }
348 else
349 {
350 GNUNET_SCHEDULER_add_now (&do_error, handle);
351 return;
352 }
353}
354
355/**
356 * Method called to with the ego we are to use for shortening
357 * during the lookup.
358 *
359 * @param cls closure contains the public key to use
360 * @param ego ego handle, NULL if not found
361 * @param ctx context for application to store data for this ego
362 * (during the lifetime of this process, initially NULL)
363 * @param name name assigned by the user for this ego,
364 * NULL if the user just deleted the ego and it
365 * must thus no longer be used
366 */
367static void
368identity_shorten_cb (void *cls,
369 struct GNUNET_IDENTITY_Ego *ego,
370 void **ctx,
371 const char *name)
372{
373 struct LookupHandle *handle = cls;
374
375 handle->id_op = NULL;
376 if (NULL == ego)
377 lookup_with_keys (handle, NULL);
378 else
379 lookup_with_keys (handle,
380 GNUNET_IDENTITY_ego_get_private_key (ego));
381}
382
383/**
384 * Perform the actual resolution, starting with the zone
385 * identified by the given public key.
386 *
387 * @param pkey public key to use for the zone
388 */
389static void
390lookup_with_public_key (struct LookupHandle *handle)
391{
392 handle->pkeym = handle->pkey;
393 GNUNET_break (NULL == handle->id_op);
394 handle->id_op = GNUNET_IDENTITY_get (handle->identity,
395 "gns-short",
396 &identity_shorten_cb,
397 handle);
398 if (NULL == handle->id_op)
399 {
400 GNUNET_break (0);
401 lookup_with_keys (handle, NULL);
402 }
403}
404
405/**
406 * Method called to with the ego we are to use for the lookup,
407 * when the ego is determined by a name.
408 *
409 * @param cls closure (NULL, unused)
410 * @param ego ego handle, NULL if not found
411 */
412static void
413identity_zone_cb (void *cls,
414 const struct GNUNET_IDENTITY_Ego *ego)
415{
416 struct LookupHandle *handle = cls;
417
418 handle->el = NULL;
419 if (NULL == ego)
420 {
421 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
422 _("Ego for not found, cannot perform lookup.\n"));
423 GNUNET_SCHEDULER_add_now (&do_error, handle);
424 return;
425 }
426 else
427 {
428 GNUNET_IDENTITY_ego_get_public_key (ego, &handle->pkey);
429 lookup_with_public_key (handle);
430 }
431 json_decref(handle->json_root);
432}
433
434/**
435 * Method called to with the ego we are to use for the lookup,
436 * when the ego is the one for the default master zone.
437 *
438 * @param cls closure (NULL, unused)
439 * @param ego ego handle, NULL if not found
440 * @param ctx context for application to store data for this ego
441 * (during the lifetime of this process, initially NULL)
442 * @param name name assigned by the user for this ego,
443 * NULL if the user just deleted the ego and it
444 * must thus no longer be used
445 */
446static void
447identity_master_cb (void *cls,
448 struct GNUNET_IDENTITY_Ego *ego,
449 void **ctx,
450 const char *name)
451{
452 const char *dot;
453 struct LookupHandle *handle = cls;
454
455 handle->id_op = NULL;
456 if (NULL == ego)
457 {
458 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
459 _("Ego for `gns-master' not found, cannot perform lookup. Did you run gnunet-gns-import.sh?\n"));
460 GNUNET_SCHEDULER_add_now (&do_error, handle);
461 return;
462 }
463 GNUNET_IDENTITY_ego_get_public_key (ego, &handle->pkey);
464 /* main name is our own master zone, do no look for that in the DHT */
465 handle->options = GNUNET_GNS_LO_LOCAL_MASTER;
466 /* if the name is of the form 'label.gnu', never go to the DHT */
467 dot = NULL;
468 if (NULL != handle->name)
469 dot = strchr (handle->name, '.');
470 if ( (NULL != dot) &&
471 (0 == strcasecmp (dot, ".gnu")) )
472 handle->options = GNUNET_GNS_LO_NO_DHT;
473 lookup_with_public_key (handle);
474}
475
476/**
477 * Parse REST uri for name and record type
478 *
479 * @param url Url to parse
480 * @param handle lookup handle to populate
481 * @return GNUNET_SYSERR on error
482 */
483static int
484parse_url (const char *url, struct LookupHandle *handle)
485{
486 char *name;
487 char tmp_url[strlen(url)+1];
488 char *tok;
489
490 strcpy (tmp_url, url);
491 tok = strtok ((char*)tmp_url, "/");
492 if (NULL == tok)
493 return GNUNET_SYSERR;
494 name = strtok (NULL, "/");
495 if (NULL == name)
496 return GNUNET_SYSERR;
497 GNUNET_asprintf (&handle->name,
498 "%s",
499 name);
500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
501 "Got name: %s\n", handle->name);
502 return GNUNET_OK;
503}
504
505static void
506get_gns_cont (struct RestConnectionDataHandle *conndata_handle,
507 const char* url,
508 void *cls)
509{
510 struct LookupHandle *handle = cls;
511 struct GNUNET_HashCode key;
512
513 //parse name and type from url
514 if (GNUNET_OK != parse_url (url, handle))
515 {
516 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error parsing url...\n");
517 GNUNET_SCHEDULER_add_now (&do_error, handle);
518 return;
519 }
520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
521 "Connecting...\n");
522 handle->gns = GNUNET_GNS_connect (cfg);
523 handle->identity = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
524 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
525 &do_error, handle);
526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
527 "Connected\n");
528 if (NULL == handle->gns)
529 {
530 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
531 "Connecting to GNS failed\n");
532 GNUNET_SCHEDULER_add_now (&do_error, handle);
533 return;
534 }
535 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_OPTIONS,
536 strlen (GNUNET_REST_JSONAPI_GNS_OPTIONS),
537 &key);
538 handle->options = GNUNET_GNS_LO_DEFAULT;
539 if ( GNUNET_YES ==
540 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
541 &key) )
542 {
543 handle->options = GNUNET_GNS_LO_DEFAULT;//TODO(char*) GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
544 //&key);
545 }
546 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_RECORD_TYPE,
547 strlen (GNUNET_REST_JSONAPI_GNS_RECORD_TYPE),
548 &key);
549 if ( GNUNET_YES ==
550 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
551 &key) )
552 {
553 handle->type = GNUNET_GNSRECORD_typename_to_number
554 (GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
555 &key));
556 }
557 else
558 handle->type = GNUNET_GNSRECORD_TYPE_ANY;
559
560 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_PKEY,
561 strlen (GNUNET_REST_JSONAPI_GNS_PKEY),
562 &key);
563 if ( GNUNET_YES ==
564 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
565 &key) )
566 {
567 handle->pkey_str = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
568 &key);
569 if (GNUNET_OK !=
570 GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->pkey_str,
571 strlen(handle->pkey_str),
572 &(handle->pkey)))
573 {
574 GNUNET_SCHEDULER_add_now (&do_error, handle);
575 return;
576 }
577 lookup_with_public_key (handle);
578 return;
579 }
580 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_EGO,
581 strlen (GNUNET_REST_JSONAPI_GNS_EGO),
582 &key);
583 if ( GNUNET_YES ==
584 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
585 &key) )
586 {
587 handle->ego_str = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
588 &key);
589 handle->el = GNUNET_IDENTITY_ego_lookup (cfg,
590 handle->ego_str,
591 &identity_zone_cb,
592 handle);
593 return;
594 }
595 if ( (NULL != handle->name) &&
596 (strlen (handle->name) > 4) &&
597 (0 == strcmp (".zkey",
598 &handle->name[strlen (handle->name) - 4])) )
599 {
600 GNUNET_CRYPTO_ecdsa_key_get_public
601 (GNUNET_CRYPTO_ecdsa_key_get_anonymous (),
602 &(handle->pkey));
603 lookup_with_public_key (handle);
604 }
605 else
606 {
607 GNUNET_break (NULL == handle->id_op);
608 handle->id_op = GNUNET_IDENTITY_get (handle->identity,
609 "gns-master",
610 &identity_master_cb,
611 handle);
612 GNUNET_assert (NULL != handle->id_op);
613 }
614}
615
616/**
617 * Handle rest request
618 *
619 * @param handle the lookup handle
620 */
621static void
622options_cont (struct RestConnectionDataHandle *con_handle,
623 const char* url,
624 void *cls)
625{
626 struct MHD_Response *resp;
627 struct LookupHandle *handle = cls;
628
629 //For GNS, independent of path return all options
630 resp = GNUNET_REST_create_json_response (NULL);
631 MHD_add_response_header (resp,
632 "Access-Control-Allow-Methods",
633 MHD_HTTP_METHOD_GET);
634 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
635 cleanup_handle (handle);
636 return;
637}
638
639
640/**
641 * Function processing the REST call
642 *
643 * @param method HTTP method
644 * @param url URL of the HTTP request
645 * @param data body of the HTTP request (optional)
646 * @param data_size length of the body
647 * @param proc callback function for the result
648 * @param proc_cls closure for callback function
649 * @return GNUNET_OK if request accepted
650 */
651static void
652rest_gns_process_request(struct RestConnectionDataHandle *conndata_handle,
653 GNUNET_REST_ResultProcessor proc,
654 void *proc_cls)
655{
656 struct LookupHandle *handle = GNUNET_new (struct LookupHandle);
657
658 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
659 handle->proc_cls = proc_cls;
660 handle->proc = proc;
661
662 static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
663 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_GNS, &get_gns_cont},
664 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_GNS, &options_cont},
665 GNUNET_REST_HANDLER_END
666 };
667
668 if (GNUNET_NO == GNUNET_REST_handle_request (conndata_handle, handlers, handle))
669 GNUNET_SCHEDULER_add_now (&do_error, handle);
670}
671
672
673
674/**
675 * Entry point for the plugin.
676 *
677 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
678 * @return NULL on error, otherwise the plugin context
679 */
680void *
681libgnunet_plugin_rest_gns_init (void *cls)
682{
683 static struct Plugin plugin;
684 cfg = cls;
685 struct GNUNET_REST_Plugin *api;
686
687 if (NULL != plugin.cfg)
688 return NULL; /* can only initialize once! */
689 memset (&plugin, 0, sizeof (struct Plugin));
690 plugin.cfg = cfg;
691 api = GNUNET_new (struct GNUNET_REST_Plugin);
692 api->cls = &plugin;
693 api->name = GNUNET_REST_API_NS_GNS;
694 api->process_request = &rest_gns_process_request;
695 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
696 _("GNS REST API initialized\n"));
697 return api;
698}
699
700
701/**
702 * Exit point from the plugin.
703 *
704 * @param cls the plugin context (as returned by "init")
705 * @return always NULL
706 */
707void *
708libgnunet_plugin_rest_gns_done (void *cls)
709{
710 struct GNUNET_REST_Plugin *api = cls;
711 struct Plugin *plugin = api->cls;
712
713 plugin->cfg = NULL;
714 GNUNET_free (api);
715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
716 "GNS REST plugin is finished\n");
717 return NULL;
718}
719
720/* end of plugin_rest_gns.c */
diff --git a/src/rest/plugin_rest_identity.c b/src/rest/plugin_rest_identity.c
deleted file mode 100644
index e5abe00ee..000000000
--- a/src/rest/plugin_rest_identity.c
+++ /dev/null
@@ -1,1080 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20/**
21 * @author Martin Schanzenbach
22 * @file identity/plugin_rest_identity.c
23 * @brief GNUnet Namestore REST plugin
24 *
25 */
26
27#include "platform.h"
28#include "gnunet_rest_plugin.h"
29#include "gnunet_identity_service.h"
30#include "gnunet_rest_lib.h"
31#include "microhttpd.h"
32#include <jansson.h>
33#include "gnunet_signatures.h"
34
35/**
36 * REST root namespace
37 */
38#define GNUNET_REST_API_NS_IDENTITY "/identity"
39
40/**
41 * State while collecting all egos
42 */
43#define ID_REST_STATE_INIT 0
44
45/**
46 * Done collecting egos
47 */
48#define ID_REST_STATE_POST_INIT 1
49
50/**
51 * Resource type
52 */
53#define GNUNET_REST_JSONAPI_IDENTITY_EGO "ego"
54
55/**
56 * Name attribute
57 */
58#define GNUNET_REST_JSONAPI_IDENTITY_NAME "name"
59
60/**
61 * Attribute to rename "name" TODO we changed id to the pubkey
62 * so this can be unified with "name"
63 */
64#define GNUNET_REST_JSONAPI_IDENTITY_NEWNAME "newname"
65
66/**
67 * URL parameter to change the subsytem for ego
68 */
69#define GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM "subsystem"
70
71
72/**
73 * URL parameter to create a GNUid token for a specific audience
74 */
75#define GNUNET_REST_JSONAPI_IDENTITY_CREATE_TOKEN "create_token_for"
76
77/**
78 * Attribute containing the GNUid token if
79 * GNUNET_REST_JSONAPI_IDENTITY_CREATE_TOKEN was requested
80 */
81#define GNUNET_REST_JSONAPI_IDENTITY_GNUID "gnuid_token"
82
83/**
84 * Error messages
85 */
86#define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
87#define GNUNET_REST_ERROR_NO_DATA "No data"
88
89/**
90 * GNUid token lifetime
91 */
92#define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000
93
94/**
95 * The configuration handle
96 */
97const struct GNUNET_CONFIGURATION_Handle *cfg;
98
99/**
100 * HTTP methods allows for this plugin
101 */
102static char* allow_methods;
103
104/**
105 * @brief struct returned by the initialization function of the plugin
106 */
107struct Plugin
108{
109 const struct GNUNET_CONFIGURATION_Handle *cfg;
110};
111
112/**
113 * The ego list
114 */
115struct EgoEntry
116{
117 /**
118 * DLL
119 */
120 struct EgoEntry *next;
121
122 /**
123 * DLL
124 */
125 struct EgoEntry *prev;
126
127 /**
128 * Ego Identifier
129 */
130 char *identifier;
131
132 /**
133 * Public key string
134 */
135 char *keystring;
136
137 /**
138 * The Ego
139 */
140 struct GNUNET_IDENTITY_Ego *ego;
141};
142
143
144struct RequestHandle
145{
146 /**
147 * Ego list
148 */
149 struct EgoEntry *ego_head;
150
151 /**
152 * Ego list
153 */
154 struct EgoEntry *ego_tail;
155
156 /**
157 * Handle to the rest connection
158 */
159 struct RestConnectionDataHandle *conndata_handle;
160
161 /**
162 * The processing state
163 */
164 int state;
165
166 /**
167 * Handle to GNS service.
168 */
169 struct GNUNET_IDENTITY_Handle *identity_handle;
170
171 /**
172 * IDENTITY Operation
173 */
174 struct GNUNET_IDENTITY_Operation *op;
175
176 /**
177 * Desired timeout for the lookup (default is no timeout).
178 */
179 struct GNUNET_TIME_Relative timeout;
180
181 /**
182 * ID of a task associated with the resolution process.
183 */
184 struct GNUNET_SCHEDULER_Task * timeout_task;
185
186 /**
187 * The plugin result processor
188 */
189 GNUNET_REST_ResultProcessor proc;
190
191 /**
192 * The closure of the result processor
193 */
194 void *proc_cls;
195
196 /**
197 * The name to look up
198 */
199 char *name;
200
201 /**
202 * The subsystem set from REST
203 */
204 char *subsys;
205
206 /**
207 * The url
208 */
209 char *url;
210
211 /**
212 * The data from the REST request
213 */
214 const char* data;
215
216 /**
217 * the length of the REST data
218 */
219 size_t data_size;
220
221 /**
222 * HTTP method
223 */
224 const char* method;
225
226 /**
227 * Error response message
228 */
229 char *emsg;
230
231};
232
233
234/**
235 * Cleanup lookup handle
236 * @param handle Handle to clean up
237 */
238static void
239cleanup_handle (struct RequestHandle *handle)
240{
241 struct EgoEntry *ego_entry;
242 struct EgoEntry *ego_tmp;
243 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
244 "Cleaning up\n");
245 if (NULL != handle->name)
246 GNUNET_free (handle->name);
247 if (NULL != handle->timeout_task)
248 GNUNET_SCHEDULER_cancel (handle->timeout_task);
249 if (NULL != handle->identity_handle)
250 GNUNET_IDENTITY_disconnect (handle->identity_handle);
251 if (NULL != handle->subsys)
252 GNUNET_free (handle->subsys);
253 if (NULL != handle->url)
254 GNUNET_free (handle->url);
255 if (NULL != handle->emsg)
256 GNUNET_free (handle->emsg);
257 for (ego_entry = handle->ego_head;
258 NULL != ego_entry;)
259 {
260 ego_tmp = ego_entry;
261 ego_entry = ego_entry->next;
262 GNUNET_free (ego_tmp->identifier);
263 GNUNET_free (ego_tmp->keystring);
264 GNUNET_free (ego_tmp);
265 }
266 GNUNET_free (handle);
267}
268
269
270/**
271 * Task run on shutdown. Cleans up everything.
272 *
273 * @param cls unused
274 * @param tc scheduler context
275 */
276static void
277do_error (void *cls,
278 const struct GNUNET_SCHEDULER_TaskContext *tc)
279{
280 struct RequestHandle *handle = cls;
281 struct MHD_Response *resp;
282 char *json_error;
283
284 GNUNET_asprintf (&json_error,
285 "{Error while processing request: %s}",
286 &handle->emsg);
287
288 resp = GNUNET_REST_create_json_response (json_error);
289 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
290 cleanup_handle (handle);
291 GNUNET_free (json_error);
292}
293
294/**
295 * Build a GNUid token for identity
296 * @param handle the handle
297 * @param ego_entry the ego to build the token for
298 * @param name name of the ego
299 * @param token_aud token audience
300 * @param token the resulting gnuid token
301 */
302static void
303make_gnuid_token (struct RequestHandle *handle,
304 struct EgoEntry *ego_entry,
305 const char *name,
306 const char *token_aud,
307 char **token)
308{
309 uint64_t time;
310 uint64_t lbl;
311 char *header_str;
312 char *payload_str;
313 char *header_base64;
314 char *payload_base64;
315 char *sig_str;
316 char *lbl_str;
317 json_t *header;
318 json_t *payload;
319 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
320 struct GNUNET_CRYPTO_EcdsaSignature sig;
321 struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
322
323 time = GNUNET_TIME_absolute_get().abs_value_us;
324 lbl = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
325 GNUNET_STRINGS_base64_encode ((char*)&lbl, sizeof (uint64_t), &lbl_str);
326
327 header = json_object ();
328 json_object_set_new (header, "alg", json_string ("ED512"));
329 json_object_set_new (header, "typ", json_string ("JWT"));
330
331 payload = json_object ();
332 json_object_set_new (payload, "iss", json_string (ego_entry->keystring));
333 json_object_set_new (payload, "lbl", json_string (lbl_str));
334 json_object_set_new (payload, "sub", json_string (name));
335 json_object_set_new (payload, "nbf", json_integer (time));
336 json_object_set_new (payload, "iat", json_integer (time));
337 json_object_set_new (payload, "exp", json_integer (time+GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS));
338 json_object_set_new (payload, "aud", json_string (token_aud));
339 header_str = json_dumps (header, JSON_COMPACT);
340 GNUNET_STRINGS_base64_encode (header_str,
341 strlen (header_str),
342 &header_base64);
343 char* padding = strtok(header_base64, "=");
344 while (NULL != padding)
345 padding = strtok(NULL, "=");
346
347 payload_str = json_dumps (payload, JSON_COMPACT);
348 GNUNET_STRINGS_base64_encode (payload_str,
349 strlen (payload_str),
350 &payload_base64);
351 padding = strtok(payload_base64, "=");
352 while (NULL != padding)
353 padding = strtok(NULL, "=");
354
355 GNUNET_asprintf (token, "%s,%s", header_base64, payload_base64);
356 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
357 purpose =
358 GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
359 strlen (*token));
360 purpose->size =
361 htonl (strlen (*token) + sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
362 purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN);
363 memcpy (&purpose[1], *token, strlen (*token));
364 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (priv_key,
365 purpose,
366 &sig))
367 GNUNET_break(0);
368 GNUNET_free (*token);
369 sig_str = GNUNET_STRINGS_data_to_string_alloc (&sig,
370 sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
371 GNUNET_asprintf (token, "%s.%s.%s",
372 header_base64, payload_base64, sig_str);
373 GNUNET_free (sig_str);
374 GNUNET_free (header_str);
375 GNUNET_free (header_base64);
376 GNUNET_free (payload_str);
377 GNUNET_free (payload_base64);
378 GNUNET_free (purpose);
379 GNUNET_free (lbl_str);
380 json_decref (header);
381 json_decref (payload);
382}
383
384/**
385 * Callback for IDENTITY_get()
386 *
387 * @param cls the RequestHandle
388 * @param ego the Ego found
389 * @param ctx the context
390 * @param name the id of the ego
391 */
392static void
393get_ego_for_subsys (void *cls,
394 struct GNUNET_IDENTITY_Ego *ego,
395 void **ctx,
396 const char *name)
397{
398 struct RequestHandle *handle = cls;
399 struct JsonApiObject *json_object;
400 struct JsonApiResource *json_resource;
401 struct EgoEntry *ego_entry;
402 struct MHD_Response *resp;
403 json_t *name_json;
404 char *result_str;
405
406 json_object = GNUNET_REST_jsonapi_object_new ();
407
408 for (ego_entry = handle->ego_head;
409 NULL != ego_entry;
410 ego_entry = ego_entry->next)
411 {
412 if ( (NULL != name) && (0 != strcmp (name, ego_entry->identifier)) )
413 continue;
414 if (NULL == name)
415 continue;
416 json_resource = GNUNET_REST_jsonapi_resource_new
417 (GNUNET_REST_JSONAPI_IDENTITY_EGO, ego_entry->keystring);
418 name_json = json_string (ego_entry->identifier);
419 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
420 GNUNET_REST_JSONAPI_IDENTITY_NAME,
421 name_json);
422 json_decref (name_json);
423 GNUNET_REST_jsonapi_object_resource_add (json_object, json_resource);
424 break;
425 }
426 if (0 == GNUNET_REST_jsonapi_object_resource_count (json_object))
427 {
428 GNUNET_REST_jsonapi_object_delete (json_object);
429 handle->emsg = GNUNET_strdup("No identity matches results!");
430 GNUNET_SCHEDULER_add_now (&do_error, handle);
431 return;
432 }
433 GNUNET_REST_jsonapi_data_serialize (json_object, &result_str);
434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
435 resp = GNUNET_REST_create_json_response (result_str);
436 GNUNET_REST_jsonapi_object_delete (json_object);
437 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
438 GNUNET_free (result_str);
439 cleanup_handle (handle);
440}
441
442/**
443 * Create a response with requested ego(s)
444 *
445 * @param con the Rest handle
446 * @param url the requested url
447 * @param cls the request handle
448 */
449static void
450ego_info_response (struct RestConnectionDataHandle *con,
451 const char *url,
452 void *cls)
453{
454 const char *egoname;
455 char *result_str;
456 char *subsys_val;
457 char *create_token_for;
458 char *token;
459 char *keystring;
460 struct RequestHandle *handle = cls;
461 struct EgoEntry *ego_entry;
462 struct GNUNET_HashCode key;
463 struct MHD_Response *resp;
464 struct JsonApiObject *json_object;
465 struct JsonApiResource *json_resource;
466 json_t *name_str;
467 json_t *token_str;
468
469 if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url, GNUNET_REST_API_NS_IDENTITY))
470 {
471 resp = GNUNET_REST_create_json_response (NULL);
472 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
473 cleanup_handle (handle);
474 return;
475 }
476 egoname = NULL;
477 keystring = NULL;
478 if (strlen (GNUNET_REST_API_NS_IDENTITY) < strlen (handle->url))
479 {
480 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY)+1];
481 //Return all egos
482 for (ego_entry = handle->ego_head;
483 NULL != ego_entry;
484 ego_entry = ego_entry->next)
485 {
486 if ( (NULL != keystring) && (0 != strcmp (keystring, ego_entry->keystring)) )
487 continue;
488 egoname = ego_entry->identifier;
489 }
490 }
491
492 if ( NULL == egoname ) {
493 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM,
494 strlen (GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM),
495 &key);
496 if ( GNUNET_YES ==
497 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
498 &key) )
499 {
500 subsys_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
501 &key);
502 if (NULL != subsys_val)
503 {
504 GNUNET_asprintf (&handle->subsys, "%s", subsys_val);
505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsys_val);
506 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
507 handle->subsys,
508 &get_ego_for_subsys,
509 handle);
510 return;
511 }
512 }
513 }
514
515 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_CREATE_TOKEN,
516 strlen (GNUNET_REST_JSONAPI_IDENTITY_CREATE_TOKEN),
517 &key);
518
519 //Token audience
520 create_token_for = NULL;
521 if ( GNUNET_YES ==
522 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
523 &key) )
524 create_token_for = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
525 &key);
526
527 json_object = GNUNET_REST_jsonapi_object_new ();
528
529 //Return all egos
530 for (ego_entry = handle->ego_head;
531 NULL != ego_entry;
532 ego_entry = ego_entry->next)
533 {
534 if ( (NULL != egoname) && (0 != strcmp (egoname, ego_entry->identifier)) )
535 continue;
536 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_EGO,
537 ego_entry->keystring);
538 name_str = json_string (ego_entry->identifier);
539 GNUNET_REST_jsonapi_resource_add_attr (
540 json_resource,
541 GNUNET_REST_JSONAPI_IDENTITY_NAME,
542 name_str);
543 json_decref (name_str);
544 if (NULL != create_token_for)
545 {
546 make_gnuid_token (handle,
547 ego_entry,
548 ego_entry->identifier,
549 create_token_for,
550 &token);
551 token_str = json_string (token);
552 GNUNET_free (token);
553 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
554 GNUNET_REST_JSONAPI_IDENTITY_GNUID,
555 token_str);
556 json_decref (token_str);
557 }
558 GNUNET_REST_jsonapi_object_resource_add (json_object, json_resource);
559 }
560 if (0 == GNUNET_REST_jsonapi_object_resource_count (json_object))
561 {
562 GNUNET_REST_jsonapi_object_delete (json_object);
563 handle->emsg = GNUNET_strdup ("No identities found!");
564 GNUNET_SCHEDULER_add_now (&do_error, handle);
565 return;
566 }
567 GNUNET_REST_jsonapi_data_serialize (json_object, &result_str);
568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
569 resp = GNUNET_REST_create_json_response (result_str);
570 GNUNET_REST_jsonapi_object_delete (json_object);
571 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
572 GNUNET_free (result_str);
573 cleanup_handle (handle);
574}
575
576/**
577 * Processing finished
578 *
579 * @param cls request handle
580 * @param emsg error message
581 */
582static void
583do_finished (void *cls, const char *emsg)
584{
585 struct RequestHandle *handle = cls;
586 struct MHD_Response *resp;
587
588 handle->op = NULL;
589 if (NULL != emsg)
590 {
591 handle->emsg = GNUNET_strdup (emsg);
592 GNUNET_SCHEDULER_add_now (&do_error, handle);
593 return;
594 }
595 resp = GNUNET_REST_create_json_response (NULL);
596 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
597 cleanup_handle (handle);
598}
599
600/**
601 * Create a new ego
602 *
603 * @param con rest handle
604 * @param url url
605 * @param cls request handle
606 */
607static void
608ego_create_cont (struct RestConnectionDataHandle *con,
609 const char *url,
610 void *cls)
611{
612 struct RequestHandle *handle = cls;
613 struct EgoEntry *ego_entry;
614 struct MHD_Response *resp;
615 struct JsonApiObject *json_obj;
616 struct JsonApiResource *json_res;
617 json_t *egoname_json;
618 const char* egoname;
619 char term_data[handle->data_size+1];
620
621 if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
622 {
623 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
624 GNUNET_SCHEDULER_add_now (&do_error, handle);
625 return;
626 }
627 if (0 >= handle->data_size)
628 {
629 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
630 GNUNET_SCHEDULER_add_now (&do_error, handle);
631 return;
632 }
633 term_data[handle->data_size] = '\0';
634 memcpy (term_data, handle->data, handle->data_size);
635 json_obj = GNUNET_REST_jsonapi_object_parse (term_data);
636 if (NULL == json_obj)
637 {
638 GNUNET_SCHEDULER_add_now (&do_error, handle);
639 return;
640 }
641 if (1 != GNUNET_REST_jsonapi_object_resource_count (json_obj))
642 {
643 GNUNET_REST_jsonapi_object_delete (json_obj);
644 handle->emsg = GNUNET_strdup ("Provided resource count invalid");
645 GNUNET_SCHEDULER_add_now (&do_error, handle);
646 return;
647 }
648 json_res = GNUNET_REST_jsonapi_object_get_resource (json_obj, 0);
649 if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO))
650 {
651 GNUNET_REST_jsonapi_object_delete (json_obj);
652 resp = GNUNET_REST_create_json_response (NULL);
653 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
654 cleanup_handle (handle);
655 return;
656 }
657 egoname_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_NAME);
658 if (!json_is_string (egoname_json))
659 {
660 GNUNET_REST_jsonapi_object_delete (json_obj);
661 handle->emsg = GNUNET_strdup ("No name provided");
662 GNUNET_SCHEDULER_add_now (&do_error, handle);
663 return;
664 }
665 egoname = json_string_value (egoname_json);
666 for (ego_entry = handle->ego_head;
667 NULL != ego_entry;
668 ego_entry = ego_entry->next)
669 {
670 if (0 == strcasecmp (egoname, ego_entry->identifier))
671 {
672 GNUNET_REST_jsonapi_object_delete (json_obj);
673 resp = GNUNET_REST_create_json_response (NULL);
674 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
675 cleanup_handle (handle);
676 return;
677 }
678 }
679 GNUNET_asprintf (&handle->name, "%s", egoname);
680 GNUNET_REST_jsonapi_object_delete (json_obj);
681 handle->op = GNUNET_IDENTITY_create (handle->identity_handle,
682 handle->name,
683 &do_finished,
684 handle);
685}
686
687
688/**
689 * Handle ego edit request
690 *
691 * @param con rest connection handle
692 * @param url the url that is requested
693 * @param cls the RequestHandle
694 */
695static void
696ego_edit_cont (struct RestConnectionDataHandle *con,
697 const char *url,
698 void *cls)
699{
700 struct JsonApiObject *json_obj;
701 struct JsonApiResource *json_res;
702 struct RequestHandle *handle = cls;
703 struct EgoEntry *ego_entry;
704 struct MHD_Response *resp;
705 json_t *subsys_json;
706 json_t *name_json;
707 const char *keystring;
708 const char *subsys;
709 const char *newname;
710 char term_data[handle->data_size+1];
711 int ego_exists = GNUNET_NO;
712
713 if (strlen (GNUNET_REST_API_NS_IDENTITY) > strlen (handle->url))
714 {
715 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
716 GNUNET_SCHEDULER_add_now (&do_error, handle);
717 return;
718 }
719
720 keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
721
722 for (ego_entry = handle->ego_head;
723 NULL != ego_entry;
724 ego_entry = ego_entry->next)
725 {
726 if (0 != strcasecmp (keystring, ego_entry->keystring))
727 continue;
728 ego_exists = GNUNET_YES;
729 break;
730 }
731
732 if (GNUNET_NO == ego_exists)
733 {
734 resp = GNUNET_REST_create_json_response (NULL);
735 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
736 cleanup_handle (handle);
737 return;
738 }
739
740 if (0 >= handle->data_size)
741 {
742 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
743 GNUNET_SCHEDULER_add_now (&do_error, handle);
744 return;
745 }
746
747 term_data[handle->data_size] = '\0';
748 memcpy (term_data, handle->data, handle->data_size);
749 json_obj = GNUNET_REST_jsonapi_object_parse (term_data);
750
751 if (NULL == json_obj)
752 {
753 handle->emsg = GNUNET_strdup ("Data invalid");
754 GNUNET_SCHEDULER_add_now (&do_error, handle);
755 return;
756 }
757
758 if (1 != GNUNET_REST_jsonapi_object_resource_count (json_obj))
759 {
760 GNUNET_REST_jsonapi_object_delete (json_obj);
761 handle->emsg = GNUNET_strdup ("Resource amount invalid");
762 GNUNET_SCHEDULER_add_now (&do_error, handle);
763 return;
764 }
765 json_res = GNUNET_REST_jsonapi_object_get_resource (json_obj, 0);
766
767 if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO))
768 {
769 GNUNET_REST_jsonapi_object_delete (json_obj);
770 handle->emsg = GNUNET_strdup ("Resource type invalid");
771 GNUNET_SCHEDULER_add_now (&do_error, handle);
772 return;
773 }
774
775 //This is a rename
776 name_json = GNUNET_REST_jsonapi_resource_read_attr (json_res,
777 GNUNET_REST_JSONAPI_IDENTITY_NEWNAME);
778 if ((NULL != name_json) && json_is_string (name_json))
779 {
780 newname = json_string_value (name_json);
781 for (ego_entry = handle->ego_head;
782 NULL != ego_entry;
783 ego_entry = ego_entry->next)
784 {
785 if (0 == strcasecmp (newname, ego_entry->identifier) &&
786 0 != strcasecmp (keystring, ego_entry->keystring))
787 {
788 //Ego with same name not allowed
789 GNUNET_REST_jsonapi_object_delete (json_obj);
790 resp = GNUNET_REST_create_json_response (NULL);
791 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
792 cleanup_handle (handle);
793 return;
794 }
795 }
796 handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
797 ego_entry->identifier,
798 newname,
799 &do_finished,
800 handle);
801 GNUNET_REST_jsonapi_object_delete (json_obj);
802 return;
803 }
804
805 //Set subsystem
806 subsys_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM);
807 if ( (NULL != subsys_json) && json_is_string (subsys_json))
808 {
809 subsys = json_string_value (subsys_json);
810 GNUNET_asprintf (&handle->subsys, "%s", subsys);
811 GNUNET_REST_jsonapi_object_delete (json_obj);
812 handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
813 handle->subsys,
814 ego_entry->ego,
815 &do_finished,
816 handle);
817 return;
818 }
819 GNUNET_REST_jsonapi_object_delete (json_obj);
820 handle->emsg = GNUNET_strdup ("Subsystem not provided");
821 GNUNET_SCHEDULER_add_now (&do_error, handle);
822}
823
824void
825ego_delete_cont (struct RestConnectionDataHandle *con_handle,
826 const char* url,
827 void *cls)
828{
829 const char *keystring;
830 struct EgoEntry *ego_entry;
831 struct MHD_Response *resp;
832 struct RequestHandle *handle = cls;
833 int ego_exists = GNUNET_NO;
834
835 if (strlen (GNUNET_REST_API_NS_IDENTITY) >= strlen (handle->url))
836 {
837 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
838 GNUNET_SCHEDULER_add_now (&do_error, handle);
839 return;
840 }
841
842 keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
843 for (ego_entry = handle->ego_head;
844 NULL != ego_entry;
845 ego_entry = ego_entry->next)
846 {
847 if (0 != strcasecmp (keystring, ego_entry->keystring))
848 continue;
849 ego_exists = GNUNET_YES;
850 break;
851 }
852 if (GNUNET_NO == ego_exists)
853 {
854 resp = GNUNET_REST_create_json_response (NULL);
855 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
856 cleanup_handle (handle);
857 return;
858 }
859 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
860 ego_entry->identifier,
861 &do_finished,
862 handle);
863
864}
865
866
867/**
868 * Respond to OPTIONS request
869 *
870 * @param con_handle the connection handle
871 * @param url the url
872 * @param cls the RequestHandle
873 */
874static void
875options_cont (struct RestConnectionDataHandle *con_handle,
876 const char* url,
877 void *cls)
878{
879 struct MHD_Response *resp;
880 struct RequestHandle *handle = cls;
881
882 //For now, independent of path return all options
883 resp = GNUNET_REST_create_json_response (NULL);
884 MHD_add_response_header (resp,
885 "Access-Control-Allow-Methods",
886 allow_methods);
887 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
888 cleanup_handle (handle);
889 return;
890}
891
892/**
893 * Handle rest request
894 *
895 * @param handle the request handle
896 */
897static void
898init_cont (struct RequestHandle *handle)
899{
900 static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
901 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_info_response},
902 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create_cont},
903 {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY, &ego_edit_cont},
904 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY, &ego_delete_cont},
905 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont},
906 GNUNET_REST_HANDLER_END
907 };
908
909 if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
910 {
911 handle->emsg = GNUNET_strdup ("Request unsupported");
912 GNUNET_SCHEDULER_add_now (&do_error, handle);
913 }
914}
915
916/**
917 * If listing is enabled, prints information about the egos.
918 *
919 * This function is initially called for all egos and then again
920 * whenever a ego's identifier changes or if it is deleted. At the
921 * end of the initial pass over all egos, the function is once called
922 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
923 * be invoked in the future or that there was an error.
924 *
925 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
926 * this function is only called ONCE, and 'NULL' being passed in
927 * 'ego' does indicate an error (i.e. name is taken or no default
928 * value is known). If 'ego' is non-NULL and if '*ctx'
929 * is set in those callbacks, the value WILL be passed to a subsequent
930 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
931 * that one was not NULL).
932 *
933 * When an identity is renamed, this function is called with the
934 * (known) ego but the NEW identifier.
935 *
936 * When an identity is deleted, this function is called with the
937 * (known) ego and "NULL" for the 'identifier'. In this case,
938 * the 'ego' is henceforth invalid (and the 'ctx' should also be
939 * cleaned up).
940 *
941 * @param cls closure
942 * @param ego ego handle
943 * @param ctx context for application to store data for this ego
944 * (during the lifetime of this process, initially NULL)
945 * @param identifier identifier assigned by the user for this ego,
946 * NULL if the user just deleted the ego and it
947 * must thus no longer be used
948 */
949static void
950list_ego (void *cls,
951 struct GNUNET_IDENTITY_Ego *ego,
952 void **ctx,
953 const char *identifier)
954{
955 struct RequestHandle *handle = cls;
956 struct EgoEntry *ego_entry;
957 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
958
959 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
960 {
961 handle->state = ID_REST_STATE_POST_INIT;
962 init_cont (handle);
963 return;
964 }
965 if (ID_REST_STATE_INIT == handle->state) {
966 ego_entry = GNUNET_new (struct EgoEntry);
967 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
968 ego_entry->keystring =
969 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
970 ego_entry->ego = ego;
971 GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
972 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
973 }
974
975}
976
977/**
978 * Function processing the REST call
979 *
980 * @param method HTTP method
981 * @param url URL of the HTTP request
982 * @param data body of the HTTP request (optional)
983 * @param data_size length of the body
984 * @param proc callback function for the result
985 * @param proc_cls closure for callback function
986 * @return GNUNET_OK if request accepted
987 */
988static void
989rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
990 GNUNET_REST_ResultProcessor proc,
991 void *proc_cls)
992{
993 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
994
995
996
997 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
998
999 handle->proc_cls = proc_cls;
1000 handle->proc = proc;
1001 handle->state = ID_REST_STATE_INIT;
1002 handle->conndata_handle = conndata_handle;
1003 handle->data = conndata_handle->data;
1004 handle->data_size = conndata_handle->data_size;
1005 handle->method = conndata_handle->method;
1006 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
1007 if (handle->url[strlen (handle->url)-1] == '/')
1008 handle->url[strlen (handle->url)-1] = '\0';
1009 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1010 "Connecting...\n");
1011 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1012 &list_ego,
1013 handle);
1014 GNUNET_strdup ("Timeout");
1015 handle->timeout_task =
1016 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1017 &do_error,
1018 handle);
1019
1020
1021 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1022 "Connected\n");
1023}
1024
1025/**
1026 * Entry point for the plugin.
1027 *
1028 * @param cls Config info
1029 * @return NULL on error, otherwise the plugin context
1030 */
1031void *
1032libgnunet_plugin_rest_identity_init (void *cls)
1033{
1034 static struct Plugin plugin;
1035 struct GNUNET_REST_Plugin *api;
1036
1037 cfg = cls;
1038 if (NULL != plugin.cfg)
1039 return NULL; /* can only initialize once! */
1040 memset (&plugin, 0, sizeof (struct Plugin));
1041 plugin.cfg = cfg;
1042 api = GNUNET_new (struct GNUNET_REST_Plugin);
1043 api->cls = &plugin;
1044 api->name = GNUNET_REST_API_NS_IDENTITY;
1045 api->process_request = &rest_identity_process_request;
1046 GNUNET_asprintf (&allow_methods,
1047 "%s, %s, %s, %s, %s",
1048 MHD_HTTP_METHOD_GET,
1049 MHD_HTTP_METHOD_POST,
1050 MHD_HTTP_METHOD_PUT,
1051 MHD_HTTP_METHOD_DELETE,
1052 MHD_HTTP_METHOD_OPTIONS);
1053
1054 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1055 _("Identity REST API initialized\n"));
1056 return api;
1057}
1058
1059
1060/**
1061 * Exit point from the plugin.
1062 *
1063 * @param cls the plugin context (as returned by "init")
1064 * @return always NULL
1065 */
1066void *
1067libgnunet_plugin_rest_identity_done (void *cls)
1068{
1069 struct GNUNET_REST_Plugin *api = cls;
1070 struct Plugin *plugin = api->cls;
1071
1072 plugin->cfg = NULL;
1073 GNUNET_free_non_null (allow_methods);
1074 GNUNET_free (api);
1075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1076 "Identity REST plugin is finished\n");
1077 return NULL;
1078}
1079
1080/* end of plugin_rest_gns.c */
diff --git a/src/rest/plugin_rest_namestore.c b/src/rest/plugin_rest_namestore.c
deleted file mode 100644
index 5ece83064..000000000
--- a/src/rest/plugin_rest_namestore.c
+++ /dev/null
@@ -1,1107 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20/**
21 * @author Martin Schanzenbach
22 * @file namestore/plugin_rest_namestore.c
23 * @brief GNUnet Namestore REST plugin
24 *
25 */
26
27#include "platform.h"
28#include "gnunet_rest_plugin.h"
29#include "gnunet_namestore_service.h"
30#include "gnunet_identity_service.h"
31#include "gnunet_rest_lib.h"
32#include "microhttpd.h"
33#include <jansson.h>
34
35#define GNUNET_REST_API_NS_NAMESTORE "/names"
36
37#define GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO "record"
38
39#define GNUNET_REST_JSONAPI_NAMESTORE_RECORD GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO
40
41#define GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE "record_type"
42
43#define GNUNET_REST_JSONAPI_NAMESTORE_VALUE "value"
44
45#define GNUNET_REST_JSONAPI_NAMESTORE_PUBLIC "public"
46
47#define GNUNET_REST_JSONAPI_NAMESTORE_SHADOW "shadow"
48
49#define GNUNET_REST_JSONAPI_NAMESTORE_PKEY "pkey"
50
51#define GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION "expiration"
52
53#define GNUNET_REST_JSONAPI_NAMESTORE_EGO "ego"
54
55/**
56 * @brief struct returned by the initialization function of the plugin
57 */
58struct Plugin
59{
60 const struct GNUNET_CONFIGURATION_Handle *cfg;
61};
62
63
64/**
65 * HTTP methods allows for this plugin
66 */
67static char* allow_methods;
68
69const struct GNUNET_CONFIGURATION_Handle *cfg;
70
71struct RecordEntry
72{
73 /**
74 * DLL
75 */
76 struct RecordEntry *next;
77
78 /**
79 * DLL
80 */
81 struct RecordEntry *prev;
82
83};
84
85struct RequestHandle
86{
87 /**
88 * Ego list
89 */
90 struct RecordEntry *record_head;
91
92 /**
93 * Ego list
94 */
95 struct record_entry *record_tail;
96
97 /**
98 * JSON response object
99 */
100 struct JsonApiObject *resp_object;
101
102 /**
103 * Rest connection
104 */
105 struct RestConnectionDataHandle *conndata_handle;
106
107 /**
108 * Handle to GNS service.
109 */
110 struct GNUNET_IDENTITY_Handle *identity_handle;
111
112 /**
113 * Handle to NAMESTORE
114 */
115 struct GNUNET_NAMESTORE_Handle *ns_handle;
116
117 /**
118 * Handle to NAMESTORE it
119 */
120 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
121
122 /**
123 * Private key for the zone
124 */
125 struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
126
127 /**
128 * Handle to identity lookup
129 */
130 struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
131
132 /**
133 * Default Ego operation
134 */
135 struct GNUNET_IDENTITY_Operation *get_default;
136
137 /**
138 * Name of the ego
139 */
140 char *ego_name;
141
142 /**
143 * Record is public
144 */
145 int is_public;
146
147 /**
148 * Shadow record
149 */
150 int is_shadow;
151
152 /**
153 * Name of the record to modify
154 */
155 char *name;
156
157 /**
158 * Value of the record
159 */
160 char *value;
161
162 /**
163 * record type
164 */
165 uint32_t type;
166
167 /**
168 * Records to store
169 */
170 struct GNUNET_GNSRECORD_Data *rd;
171
172 /**
173 * record count
174 */
175 unsigned int rd_count;
176
177 /**
178 * NAMESTORE Operation
179 */
180 struct GNUNET_NAMESTORE_QueueEntry *add_qe;
181
182 /**
183 * Desired timeout for the lookup (default is no timeout).
184 */
185 struct GNUNET_TIME_Relative timeout;
186
187 /**
188 * ID of a task associated with the resolution process.
189 */
190 struct GNUNET_SCHEDULER_Task * timeout_task;
191
192 /**
193 * The plugin result processor
194 */
195 GNUNET_REST_ResultProcessor proc;
196
197 /**
198 * The closure of the result processor
199 */
200 void *proc_cls;
201
202 /**
203 * The url
204 */
205 char *url;
206
207 /**
208 * The data from the REST request
209 */
210 const char* data;
211
212 /**
213 * the length of the REST data
214 */
215 size_t data_size;
216
217 /**
218 * Cfg
219 */
220 const struct GNUNET_CONFIGURATION_Handle *cfg;
221
222};
223
224
225/**
226 * Cleanup lookup handle
227 * @param handle Handle to clean up
228 */
229static void
230cleanup_handle (struct RequestHandle *handle)
231{
232 struct RecordEntry *record_entry;
233 struct RecordEntry *record_tmp;
234 int i;
235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
236 "Cleaning up\n");
237 if (NULL != handle->name)
238 GNUNET_free (handle->name);
239 if (NULL != handle->timeout_task)
240 GNUNET_SCHEDULER_cancel (handle->timeout_task);
241 if (NULL != handle->ego_lookup)
242 GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
243 if (NULL != handle->get_default)
244 GNUNET_IDENTITY_cancel (handle->get_default);
245 if (NULL != handle->list_it)
246 GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
247 if (NULL != handle->add_qe)
248 GNUNET_NAMESTORE_cancel (handle->add_qe);
249 if (NULL != handle->identity_handle)
250 GNUNET_IDENTITY_disconnect (handle->identity_handle);
251 if (NULL != handle->ns_handle)
252 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
253 if (NULL != handle->url)
254 GNUNET_free (handle->url);
255 if (NULL != handle->value)
256 GNUNET_free (handle->value);
257 if (NULL != handle->rd)
258 {
259 for (i = 0; i < handle->rd_count; i++)
260 {
261 if (NULL != handle->rd[i].data)
262 GNUNET_free ((void*)handle->rd[i].data);
263 }
264 GNUNET_free (handle->rd);
265 }
266 if (NULL != handle->ego_name)
267 GNUNET_free (handle->ego_name);
268 for (record_entry = handle->record_head;
269 NULL != record_entry;)
270 {
271 record_tmp = record_entry;
272 record_entry = record_entry->next;
273 GNUNET_free (record_tmp);
274 }
275 GNUNET_free (handle);
276}
277
278/**
279 * Create json representation of a GNSRECORD
280 *
281 * @param rd the GNSRECORD_Data
282 */
283static json_t *
284gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
285{
286 const char *typename;
287 char *string_val;
288 const char *exp_str;
289 json_t *record_obj;
290
291 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
292 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
293 rd->data,
294 rd->data_size);
295
296 if (NULL == string_val)
297 {
298 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
299 "Record of type %d malformed, skipping\n",
300 (int) rd->record_type);
301 return NULL;
302 }
303 record_obj = json_object();
304 json_object_set_new (record_obj,
305 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
306 json_string (typename));
307 json_object_set_new (record_obj,
308 GNUNET_REST_JSONAPI_NAMESTORE_VALUE,
309 json_string (string_val));
310 GNUNET_free (string_val);
311
312 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
313 {
314 struct GNUNET_TIME_Relative time_rel;
315 time_rel.rel_value_us = rd->expiration_time;
316 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
317 }
318 else
319 {
320 struct GNUNET_TIME_Absolute time_abs;
321 time_abs.abs_value_us = rd->expiration_time;
322 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
323 }
324 json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str));
325
326 json_object_set_new (record_obj, "expired",
327 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
328 return record_obj;
329}
330
331
332/**
333 * Task run on shutdown. Cleans up everything.
334 *
335 * @param cls unused
336 * @param tc scheduler context
337 */
338static void
339do_error (void *cls,
340 const struct GNUNET_SCHEDULER_TaskContext *tc)
341{
342 struct RequestHandle *handle = cls;
343 struct MHD_Response *resp = GNUNET_REST_create_json_response (NULL);
344 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
345 cleanup_handle (handle);
346}
347
348static void
349cleanup_handle_delayed (void *cls,
350 const struct GNUNET_SCHEDULER_TaskContext *tc)
351{
352 cleanup_handle (cls);
353}
354
355/**
356 * Create a response with requested records
357 *
358 * @param handle the RequestHandle
359 */
360static void
361namestore_list_response (void *cls,
362 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
363 const char *rname,
364 unsigned int rd_len,
365 const struct GNUNET_GNSRECORD_Data *rd)
366{
367 struct RequestHandle *handle = cls;
368 struct JsonApiResource *json_resource;
369 struct MHD_Response *resp;
370 json_t *result_array;
371 json_t *record_obj;
372 int i;
373 char *result;
374
375 if (NULL == handle->resp_object)
376 handle->resp_object = GNUNET_REST_jsonapi_object_new ();
377
378 if (NULL == rname)
379 {
380 handle->list_it = NULL;
381 //Handle response
382 if (GNUNET_SYSERR == GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result))
383 {
384 GNUNET_SCHEDULER_add_now (&do_error, handle);
385 return;
386 }
387 GNUNET_REST_jsonapi_object_delete (handle->resp_object);
388 resp = GNUNET_REST_create_json_response (result);
389 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
390 GNUNET_free (result);
391 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
392 return;
393 }
394
395 if ( (NULL != handle->name) &&
396 (0 != strcmp (handle->name, rname)) )
397 {
398 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
399 "%s does not match %s\n", rname, handle->name);
400 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
401 return;
402 }
403
404 result_array = json_array ();
405 for (i=0; i<rd_len; i++)
406 {
407 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
408 (0 != strcmp (rname, "+")) )
409 continue;
410
411 if ( (rd[i].record_type != handle->type) &&
412 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
413 continue;
414 record_obj = gnsrecord_to_json (&(rd[i]));
415 json_array_append (result_array, record_obj);
416 json_decref (record_obj);
417 }
418
419 if (0 < json_array_size(result_array))
420 {
421 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
422 rname);
423 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
424 GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
425 result_array);
426 GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
427 }
428
429 json_decref (result_array);
430 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
431}
432
433static void
434create_finished (void *cls, int32_t success, const char *emsg)
435{
436 struct RequestHandle *handle = cls;
437 struct MHD_Response *resp;
438
439 handle->add_qe = NULL;
440 if (GNUNET_YES != success)
441 {
442 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
443 "Error storing records%s%s\n",
444 (NULL == emsg) ? "" : ": ",
445 (NULL == emsg) ? "" : emsg);
446 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
447 return;
448 }
449 resp = GNUNET_REST_create_json_response (NULL);
450 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
451 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
452}
453
454
455/**
456 * We're storing a new record; this requires
457 * that no record already exists
458 *
459 * @param cls closure, unused
460 * @param zone_key private key of the zone
461 * @param rec_name name that is being mapped (at most 255 characters long)
462 * @param rd_count number of entries in @a rd array
463 * @param rd array of records with data to store
464 */
465static void
466create_new_record_cont (void *cls,
467 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
468 const char *rec_name,
469 unsigned int rd_count,
470 const struct GNUNET_GNSRECORD_Data *rd)
471{
472 struct RequestHandle *handle = cls;
473
474 handle->add_qe = NULL;
475 if ( (NULL != zone_key) &&
476 (0 != strcmp (rec_name, handle->name)) )
477 {
478 GNUNET_break (0);
479 GNUNET_SCHEDULER_add_now (&do_error, handle);
480 return;
481 }
482
483 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
484 "Received %u records for name `%s'\n",
485 rd_count, rec_name);
486 if (0 != rd_count)
487 {
488 handle->proc (handle->proc_cls,
489 GNUNET_REST_create_json_response (NULL),
490 MHD_HTTP_CONFLICT);
491 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
492 return;
493 }
494
495 GNUNET_assert (NULL != handle->name);
496 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
497 &handle->zone_pkey,
498 handle->name,
499 handle->rd_count,
500 handle->rd,
501 &create_finished,
502 handle);
503}
504
505static void
506del_finished (void *cls,
507 int32_t success,
508 const char *emsg)
509{
510 struct RequestHandle *handle = cls;
511
512 handle->add_qe = NULL;
513 if (GNUNET_NO == success)
514 {
515 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
516 _("Deleting record failed, record does not exist%s%s\n"),
517 (NULL != emsg) ? ": " : "",
518 (NULL != emsg) ? emsg : "");
519 GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
520 return;
521 }
522 if (GNUNET_SYSERR == success)
523 {
524 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
525 _("Deleting record failed%s%s\n"),
526 (NULL != emsg) ? ": " : "",
527 (NULL != emsg) ? emsg : "");
528 GNUNET_SCHEDULER_add_now (&do_error, handle);
529 return;
530 }
531 handle->proc (handle->proc_cls,
532 GNUNET_REST_create_json_response (NULL),
533 MHD_HTTP_NO_CONTENT);
534 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
535}
536
537static void
538del_cont (void *cls,
539 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
540 const char *label,
541 unsigned int rd_count,
542 const struct GNUNET_GNSRECORD_Data *rd)
543{
544 struct RequestHandle *handle = cls;
545
546 if (0 == rd_count)
547 {
548 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
549 _("There are no records under label `%s' that could be deleted.\n"),
550 label);
551 GNUNET_SCHEDULER_add_now (&do_error, handle);
552 return;
553 }
554
555 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
556 &handle->zone_pkey,
557 handle->name,
558 0, NULL,
559 &del_finished,
560 handle);
561}
562
563static void
564namestore_delete_cont (struct RestConnectionDataHandle *con,
565 const char *url,
566 void *cls)
567{
568 struct RequestHandle *handle = cls;
569
570 if (NULL == handle->name)
571 {
572 GNUNET_SCHEDULER_add_now (&do_error, handle);
573 return;
574 }
575
576 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
577 &handle->zone_pkey,
578 handle->name,
579 &del_cont,
580 handle);
581}
582
583static int
584json_to_gnsrecord (const json_t *records_json,
585 struct GNUNET_GNSRECORD_Data **rd,
586 unsigned int *rd_count)
587{
588 struct GNUNET_TIME_Relative etime_rel;
589 struct GNUNET_TIME_Absolute etime_abs;
590 char *value;
591 void *rdata;
592 size_t rdata_size;
593 const char *typestring;
594 const char *expirationstring;
595 int i;
596 json_t *type_json;
597 json_t *value_json;
598 json_t *record_json;
599 json_t *exp_json;
600
601 *rd_count = json_array_size (records_json);
602 *rd = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Data) * *rd_count);
603 for (i = 0; i < *rd_count; i++)
604 {
605 memset (&((*rd)[i]), 0, sizeof (struct GNUNET_GNSRECORD_Data));
606 record_json = json_array_get (records_json, i);
607 type_json = json_object_get (record_json,
608 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
609 if (!json_is_string (type_json))
610 {
611 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
612 "Type property is no string\n");
613 return GNUNET_SYSERR;
614 }
615 typestring = json_string_value (type_json);
616 (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
617 if (UINT32_MAX == (*rd)[i].record_type)
618 {
619 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
620 json_string_value (type_json));
621 return GNUNET_SYSERR;
622 }
623 value_json = json_object_get (record_json,
624 GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
625 if (!json_is_string (value_json))
626 {
627 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
628 "Value property is no string\n");
629 return GNUNET_SYSERR;
630 }
631 GNUNET_asprintf (&value, "%s", json_string_value (value_json));
632 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
633 value,
634 &rdata,
635 &rdata_size))
636 {
637 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
638 value, typestring);
639 return GNUNET_SYSERR;
640 }
641 (*rd)[i].data = rdata;
642 (*rd)[i].data_size = rdata_size;
643 /**TODO
644 * if (1 == handle->is_shadow)
645 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
646 if (1 != handle->is_public)
647 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
648 */
649 exp_json = json_object_get (record_json,
650 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
651 if (!json_is_string (exp_json))
652 {
653 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
654 "Expiration property is no string\n");
655 return GNUNET_SYSERR;
656 }
657 expirationstring = json_string_value (exp_json);
658 if (0 == strcmp (expirationstring, "never"))
659 {
660 (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
661 }
662 else if (GNUNET_OK ==
663 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
664 &etime_rel))
665 {
666 (*rd)[i].expiration_time = etime_rel.rel_value_us;
667 (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
668 }
669 else if (GNUNET_OK ==
670 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
671 &etime_abs))
672 {
673 (*rd)[i].expiration_time = etime_abs.abs_value_us;
674 }
675 else
676 {
677 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
678 value, typestring);
679 return GNUNET_SYSERR;
680 }
681 }
682 return GNUNET_OK;
683}
684
685static void
686namestore_create_cont (struct RestConnectionDataHandle *con,
687 const char *url,
688 void *cls)
689{
690 struct RequestHandle *handle = cls;
691 struct MHD_Response *resp;
692 struct JsonApiObject *json_obj;
693 struct JsonApiResource *json_res;
694 json_t *name_json;
695 json_t *records_json;
696 char term_data[handle->data_size+1];
697
698 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
699 {
700 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
701 "Cannot create under %s\n", handle->url);
702 GNUNET_SCHEDULER_add_now (&do_error, handle);
703 return;
704 }
705 if (0 >= handle->data_size)
706 {
707 GNUNET_SCHEDULER_add_now (&do_error, handle);
708 return;
709 }
710 term_data[handle->data_size] = '\0';
711 memcpy (term_data, handle->data, handle->data_size);
712 json_obj = GNUNET_REST_jsonapi_object_parse (term_data);
713 if (NULL == json_obj)
714 {
715 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
716 "Unable to parse JSONAPI Object from %s\n",
717 term_data);
718 GNUNET_SCHEDULER_add_now (&do_error, handle);
719 return;
720 }
721 if (1 != GNUNET_REST_jsonapi_object_resource_count (json_obj))
722 {
723 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
724 "Cannot create more than 1 resource! (Got %d)\n",
725 GNUNET_REST_jsonapi_object_resource_count (json_obj));
726 GNUNET_REST_jsonapi_object_delete (json_obj);
727 GNUNET_SCHEDULER_add_now (&do_error, handle);
728 return;
729 }
730 json_res = GNUNET_REST_jsonapi_object_get_resource (json_obj, 0);
731 if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_type (json_res,
732 GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
733 {
734 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
735 "Unsupported JSON data type\n");
736 GNUNET_REST_jsonapi_object_delete (json_obj);
737 resp = GNUNET_REST_create_json_response (NULL);
738 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
739 cleanup_handle (handle);
740 return;
741 }
742 name_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_KEY_ID);
743 if (!json_is_string (name_json))
744 {
745 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
746 "Name property is no string\n");
747 GNUNET_REST_jsonapi_object_delete (json_obj);
748 GNUNET_SCHEDULER_add_now (&do_error, handle);
749 return;
750 }
751 GNUNET_asprintf (&handle->name, "%s", json_string_value (name_json));
752 records_json = GNUNET_REST_jsonapi_resource_read_attr (json_res,
753 GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
754 if (NULL == records_json)
755 {
756 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
757 "No records given\n");
758 GNUNET_REST_jsonapi_object_delete (json_obj);
759 GNUNET_SCHEDULER_add_now (&do_error, handle);
760 return;
761 }
762 if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
763 {
764 GNUNET_REST_jsonapi_object_delete (json_obj);
765 GNUNET_SCHEDULER_add_now (&do_error, handle);
766 return;
767 }
768 GNUNET_REST_jsonapi_object_delete (json_obj);
769
770 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
771 &handle->zone_pkey,
772 handle->name,
773 &create_new_record_cont, handle );
774}
775
776
777
778
779
780static void
781namestore_info_cont (struct RestConnectionDataHandle *con,
782 const char *url,
783 void *cls)
784{
785 struct RequestHandle *handle = cls;
786 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
787 &handle->zone_pkey,
788 &namestore_list_response,
789 handle);
790}
791
792static char*
793get_name_from_url (const char* url)
794{
795 if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
796 return NULL;
797 return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
798}
799
800/**
801 * Respond to OPTIONS request
802 *
803 * @param con_handle the connection handle
804 * @param url the url
805 * @param cls the RequestHandle
806 */
807static void
808options_cont (struct RestConnectionDataHandle *con_handle,
809 const char* url,
810 void *cls)
811{
812 struct MHD_Response *resp;
813 struct RequestHandle *handle = cls;
814
815 //For now, independent of path return all options
816 resp = GNUNET_REST_create_json_response (NULL);
817 MHD_add_response_header (resp,
818 "Access-Control-Allow-Methods",
819 allow_methods);
820 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
821 cleanup_handle (handle);
822 return;
823}
824
825/**
826 * Function called with the result from the check if the namestore
827 * service is actually running. If it is, we start the actual
828 * operation.
829 *
830 * @param cls closure with our configuration
831 * @param result #GNUNET_YES if the namestore service is running
832 */
833static void
834testservice_task (void *cls,
835 int result)
836{
837 struct RequestHandle *handle = cls;
838 static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
839 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
840 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
841 // {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
842 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
843 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
844 GNUNET_REST_HANDLER_END
845 };
846
847 if (GNUNET_YES != result)
848 {
849 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Service `%s' is not running\n"),
850 "namestore");
851 GNUNET_SCHEDULER_add_now (&do_error, handle);
852 return;
853 }
854 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
855 if (NULL == handle->ns_handle)
856 {
857 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
858 _("Failed to connect to namestore\n"));
859 GNUNET_SCHEDULER_add_now (&do_error, handle);
860 return;
861 }
862
863 if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
864 GNUNET_SCHEDULER_add_now (&do_error, (void*) handle);
865
866}
867
868/**
869 * Callback invoked from identity service with ego information.
870 * An @a ego of NULL means the ego was not found.
871 *
872 * @param cls closure with the configuration
873 * @param ego an ego known to identity service, or NULL
874 */
875static void
876identity_cb (void *cls,
877 const struct GNUNET_IDENTITY_Ego *ego)
878{
879 struct RequestHandle *handle = cls;
880 struct MHD_Response *resp;
881
882 handle->ego_lookup = NULL;
883 if (NULL == ego)
884 {
885 if (NULL != handle->ego_name)
886 {
887 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
888 _("Ego `%s' not known to identity service\n"),
889 handle->ego_name);
890 }
891 resp = GNUNET_REST_create_json_response (NULL);
892 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
893 cleanup_handle (handle);
894 return;
895 }
896 handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
897 GNUNET_CLIENT_service_test ("namestore", handle->cfg,
898 GNUNET_TIME_UNIT_SECONDS,
899 &testservice_task,
900 (void *) handle);
901}
902
903static void
904default_ego_cb (void *cls,
905 struct GNUNET_IDENTITY_Ego *ego,
906 void **ctx,
907 const char *name)
908{
909 struct RequestHandle *handle = cls;
910 struct MHD_Response *resp;
911 handle->get_default = NULL;
912 if (NULL == ego)
913 {
914 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
915 _("No default ego configured in identity service\n"));
916 resp = GNUNET_REST_create_json_response (NULL);
917 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
918 cleanup_handle (handle);
919 return;
920 }
921 else
922 {
923 identity_cb (cls, ego);
924 }
925}
926
927static void
928id_connect_cb (void *cls,
929 struct GNUNET_IDENTITY_Ego *ego,
930 void **ctx,
931 const char *name)
932{
933 struct RequestHandle *handle = cls;
934 if (NULL == ego)
935 {
936 handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
937 "namestore",
938 &default_ego_cb, handle);
939 }
940}
941
942static void
943testservice_id_task (void *cls, int result)
944{
945 struct RequestHandle *handle = cls;
946 struct MHD_Response *resp;
947 struct GNUNET_HashCode key;
948 char *ego;
949 char *name;
950 char *type;
951
952 if (result != GNUNET_YES)
953 {
954 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
955 _("Identity service is not running\n"));
956 resp = GNUNET_REST_create_json_response (NULL);
957 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
958 cleanup_handle (handle);
959 return;
960 }
961 ego = NULL;
962 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
963 strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
964 &key);
965 if ( GNUNET_YES ==
966 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
967 &key) )
968 {
969 ego = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
970 &key);
971 }
972
973 handle->type = GNUNET_GNSRECORD_TYPE_ANY;
974 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
975 strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
976 &key);
977 if ( GNUNET_YES ==
978 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
979 &key) )
980 {
981 type = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
982 &key);
983
984 handle->type = GNUNET_GNSRECORD_typename_to_number (type);
985 }
986 name = get_name_from_url (handle->url);
987 if (NULL != ego)
988 GNUNET_asprintf (&handle->ego_name, "%s", ego);
989 if (NULL != name)
990 GNUNET_asprintf (&handle->name, "%s", name);
991 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", handle->ego_name);
992 if (NULL == handle->ego_name)
993 {
994 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", handle->ego_name);
995 handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
996 if (NULL == handle->identity_handle)
997 {
998 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
999 resp = GNUNET_REST_create_json_response (NULL);
1000 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1001 cleanup_handle (handle);
1002 }
1003 return;
1004 }
1005 handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1006 handle->ego_name,
1007 &identity_cb,
1008 handle);
1009}
1010
1011/**
1012 * Function processing the REST call
1013 *
1014 * @param method HTTP method
1015 * @param url URL of the HTTP request
1016 * @param data body of the HTTP request (optional)
1017 * @param data_size length of the body
1018 * @param proc callback function for the result
1019 * @param proc_cls closure for callback function
1020 * @return GNUNET_OK if request accepted
1021 */
1022static void
1023rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
1024 GNUNET_REST_ResultProcessor proc,
1025 void *proc_cls)
1026{
1027 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1028
1029 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1030 handle->proc_cls = proc_cls;
1031 handle->proc = proc;
1032 handle->conndata_handle = conndata_handle;
1033 handle->data = conndata_handle->data;
1034 handle->data_size = conndata_handle->data_size;
1035 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
1036 if (handle->url[strlen (handle->url)-1] == '/')
1037 handle->url[strlen (handle->url)-1] = '\0';
1038 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1039 "Connecting...\n");
1040 handle->cfg = cfg;
1041 GNUNET_CLIENT_service_test ("identity",
1042 cfg,
1043 GNUNET_TIME_UNIT_SECONDS,
1044 &testservice_id_task,
1045 handle);
1046 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1047 &do_error,
1048 handle);
1049
1050
1051}
1052
1053/**
1054 * Entry point for the plugin.
1055 *
1056 * @param cls Config info
1057 * @return NULL on error, otherwise the plugin context
1058 */
1059void *
1060libgnunet_plugin_rest_namestore_init (void *cls)
1061{
1062 static struct Plugin plugin;
1063 cfg = cls;
1064 struct GNUNET_REST_Plugin *api;
1065
1066 if (NULL != plugin.cfg)
1067 return NULL; /* can only initialize once! */
1068 memset (&plugin, 0, sizeof (struct Plugin));
1069 plugin.cfg = cfg;
1070 api = GNUNET_new (struct GNUNET_REST_Plugin);
1071 api->cls = &plugin;
1072 api->name = GNUNET_REST_API_NS_NAMESTORE;
1073 api->process_request = &rest_identity_process_request;
1074 GNUNET_asprintf (&allow_methods,
1075 "%s, %s, %s, %s, %s",
1076 MHD_HTTP_METHOD_GET,
1077 MHD_HTTP_METHOD_POST,
1078 MHD_HTTP_METHOD_PUT,
1079 MHD_HTTP_METHOD_DELETE,
1080 MHD_HTTP_METHOD_OPTIONS);
1081 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1082 _("Namestore REST API initialized\n"));
1083 return api;
1084}
1085
1086
1087/**
1088 * Exit point from the plugin.
1089 *
1090 * @param cls the plugin context (as returned by "init")
1091 * @return always NULL
1092 */
1093void *
1094libgnunet_plugin_rest_namestore_done (void *cls)
1095{
1096 struct GNUNET_REST_Plugin *api = cls;
1097 struct Plugin *plugin = api->cls;
1098
1099 plugin->cfg = NULL;
1100 GNUNET_free (api);
1101 GNUNET_free_non_null (allow_methods);
1102 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1103 "Namestore REST plugin is finished\n");
1104 return NULL;
1105}
1106
1107/* end of plugin_rest_namestore.c */