aboutsummaryrefslogtreecommitdiff
path: root/src/identity
diff options
context:
space:
mode:
Diffstat (limited to 'src/identity')
-rw-r--r--src/identity/Makefile.am19
-rw-r--r--src/identity/gnunet-service-identity.c2
-rw-r--r--src/identity/plugin_rest_identity.c1059
-rwxr-xr-xsrc/identity/test_plugin_rest_identity.sh159
4 files changed, 1 insertions, 1238 deletions
diff --git a/src/identity/Makefile.am b/src/identity/Makefile.am
index e7104f0c3..1f21fc65d 100644
--- a/src/identity/Makefile.am
+++ b/src/identity/Makefile.am
@@ -39,14 +39,6 @@ bin_PROGRAMS = \
39libexec_PROGRAMS = \ 39libexec_PROGRAMS = \
40 gnunet-service-identity 40 gnunet-service-identity
41 41
42if HAVE_MHD
43if HAVE_JSON
44plugin_LTLIBRARIES = \
45 libgnunet_plugin_rest_identity.la
46endif
47endif
48
49
50gnunet_service_identity_SOURCES = \ 42gnunet_service_identity_SOURCES = \
51 gnunet-service-identity.c 43 gnunet-service-identity.c
52gnunet_service_identity_LDADD = \ 44gnunet_service_identity_LDADD = \
@@ -55,17 +47,6 @@ gnunet_service_identity_LDADD = \
55 $(GN_LIBINTL) 47 $(GN_LIBINTL)
56 48
57 49
58libgnunet_plugin_rest_identity_la_SOURCES = \
59 plugin_rest_identity.c
60libgnunet_plugin_rest_identity_la_LIBADD = \
61 libgnunetidentity.la \
62 $(top_builddir)/src/rest/libgnunetrest.la \
63 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
64 $(LTLIBINTL) -ljansson -lmicrohttpd
65libgnunet_plugin_rest_identity_la_LDFLAGS = \
66 $(GN_PLUGIN_LDFLAGS)
67
68
69gnunet_identity_SOURCES = \ 50gnunet_identity_SOURCES = \
70 gnunet-identity.c 51 gnunet-identity.c
71gnunet_identity_LDADD = \ 52gnunet_identity_LDADD = \
diff --git a/src/identity/gnunet-service-identity.c b/src/identity/gnunet-service-identity.c
index 266f5ccc3..155c49cc5 100644
--- a/src/identity/gnunet-service-identity.c
+++ b/src/identity/gnunet-service-identity.c
@@ -752,7 +752,7 @@ handle_rename_message (void *cls,
752 old_name = GNUNET_strdup (old_name_tmp); 752 old_name = GNUNET_strdup (old_name_tmp);
753 GNUNET_STRINGS_utf8_tolower (old_name_tmp, old_name); 753 GNUNET_STRINGS_utf8_tolower (old_name_tmp, old_name);
754 new_name = GNUNET_strdup (&old_name_tmp[old_name_len]); 754 new_name = GNUNET_strdup (&old_name_tmp[old_name_len]);
755 GNUNET_STRINGS_utf8_tolower (&old_name_tmp[old_name_len], old_name); 755 GNUNET_STRINGS_utf8_tolower (&old_name_tmp[old_name_len], new_name);
756 756
757 /* check if new name is already in use */ 757 /* check if new name is already in use */
758 for (ego = ego_head; NULL != ego; ego = ego->next) 758 for (ego = ego_head; NULL != ego; ego = ego->next)
diff --git a/src/identity/plugin_rest_identity.c b/src/identity/plugin_rest_identity.c
deleted file mode 100644
index a518a74cc..000000000
--- a/src/identity/plugin_rest_identity.c
+++ /dev/null
@@ -1,1059 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18/**
19 * @author Martin Schanzenbach
20 * @author Philippe Buschmann
21 * @file identity/plugin_rest_identity.c
22 * @brief GNUnet Identity REST plugin
23 */
24
25#include "platform.h"
26#include "gnunet_rest_plugin.h"
27#include "gnunet_identity_service.h"
28#include "gnunet_rest_lib.h"
29#include "microhttpd.h"
30#include <jansson.h>
31
32#define GNUNET_REST_API_NS_IDENTITY "/identity"
33
34/**
35 * Parameter names
36 */
37#define GNUNET_REST_PARAM_PUBKEY "pubkey"
38#define GNUNET_REST_PARAM_SUBSYSTEM "subsystem"
39#define GNUNET_REST_PARAM_NAME "name"
40#define GNUNET_REST_PARAM_NEWNAME "newname"
41
42/**
43 * Error messages
44 */
45#define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error"
46#define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
47#define GNUNET_REST_ERROR_NO_DATA "No data"
48#define GNUNET_REST_ERROR_DATA_INVALID "Data invalid"
49
50/**
51 * State while collecting all egos
52 */
53#define ID_REST_STATE_INIT 0
54
55/**
56 * Done collecting egos
57 */
58#define ID_REST_STATE_POST_INIT 1
59
60/**
61 * The configuration handle
62 */
63const struct GNUNET_CONFIGURATION_Handle *cfg;
64
65/**
66 * HTTP methods allows for this plugin
67 */
68static char* allow_methods;
69
70/**
71 * @brief struct returned by the initialization function of the plugin
72 */
73struct Plugin
74{
75 const struct GNUNET_CONFIGURATION_Handle *cfg;
76};
77
78/**
79 * The ego list
80 */
81struct EgoEntry
82{
83 /**
84 * DLL
85 */
86 struct EgoEntry *next;
87
88 /**
89 * DLL
90 */
91 struct EgoEntry *prev;
92
93 /**
94 * Ego Identifier
95 */
96 char *identifier;
97
98 /**
99 * Public key string
100 */
101 char *keystring;
102
103 /**
104 * The Ego
105 */
106 struct GNUNET_IDENTITY_Ego *ego;
107};
108
109struct RequestHandle
110{
111 /**
112 * The data from the REST request
113 */
114 const char* data;
115
116 /**
117 * The name to look up
118 */
119 char *name;
120
121 /**
122 * the length of the REST data
123 */
124 size_t data_size;
125
126 /**
127 * Requested Subsystem
128 */
129 char *subsystem;
130
131 /**
132 * Ego list
133 */
134 struct EgoEntry *ego_head;
135
136 /**
137 * Ego list
138 */
139 struct EgoEntry *ego_tail;
140
141 /**
142 * The processing state
143 */
144 int state;
145
146 /**
147 * Handle to Identity service.
148 */
149 struct GNUNET_IDENTITY_Handle *identity_handle;
150
151 /**
152 * IDENTITY Operation
153 */
154 struct GNUNET_IDENTITY_Operation *op;
155
156 /**
157 * Rest connection
158 */
159 struct GNUNET_REST_RequestHandle *rest_handle;
160
161 /**
162 * Desired timeout for the lookup (default is no timeout).
163 */
164 struct GNUNET_TIME_Relative timeout;
165
166 /**
167 * ID of a task associated with the resolution process.
168 */
169 struct GNUNET_SCHEDULER_Task *timeout_task;
170
171 /**
172 * The plugin result processor
173 */
174 GNUNET_REST_ResultProcessor proc;
175
176 /**
177 * The closure of the result processor
178 */
179 void *proc_cls;
180
181 /**
182 * The url
183 */
184 char *url;
185
186 /**
187 * Error response message
188 */
189 char *emsg;
190
191 /**
192 * Reponse code
193 */
194 int response_code;
195
196};
197
198/**
199 * Cleanup lookup handle
200 * @param handle Handle to clean up
201 */
202static void
203cleanup_handle (void *cls)
204{
205 struct RequestHandle *handle = cls;
206 struct EgoEntry *ego_entry;
207 struct EgoEntry *ego_tmp;
208
209 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
210 if (NULL != handle->timeout_task)
211 {
212 GNUNET_SCHEDULER_cancel (handle->timeout_task);
213 handle->timeout_task = NULL;
214 }
215
216 if (NULL != handle->subsystem)
217 GNUNET_free(handle->subsystem);
218 if (NULL != handle->url)
219 GNUNET_free(handle->url);
220 if (NULL != handle->emsg)
221 GNUNET_free(handle->emsg);
222 if (NULL != handle->name)
223 GNUNET_free (handle->name);
224 if (NULL != handle->identity_handle)
225 GNUNET_IDENTITY_disconnect (handle->identity_handle);
226
227 for (ego_entry = handle->ego_head;
228 NULL != ego_entry;)
229 {
230 ego_tmp = ego_entry;
231 ego_entry = ego_entry->next;
232 GNUNET_free(ego_tmp->identifier);
233 GNUNET_free(ego_tmp->keystring);
234 GNUNET_free(ego_tmp);
235 }
236
237 GNUNET_free(handle);
238}
239
240/**
241 * Task run on errors. Reports an error and cleans up everything.
242 *
243 * @param cls the `struct RequestHandle`
244 */
245static void
246do_error (void *cls)
247{
248 struct RequestHandle *handle = cls;
249 struct MHD_Response *resp;
250 json_t *json_error = json_object();
251 char *response;
252
253 if (NULL == handle->emsg)
254 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_ERROR_UNKNOWN);
255
256 json_object_set_new(json_error,"error", json_string(handle->emsg));
257
258 if (0 == handle->response_code)
259 handle->response_code = MHD_HTTP_OK;
260 response = json_dumps (json_error, 0);
261 resp = GNUNET_REST_create_response (response);
262 handle->proc (handle->proc_cls, resp, handle->response_code);
263 json_decref(json_error);
264 GNUNET_free(response);
265 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
266}
267
268
269
270/**
271 * Get EgoEntry from list with either a public key or a name
272 * If public key and name are not NULL, it returns the public key result first
273 *
274 * @param handle the RequestHandle
275 * @param pubkey the public key of an identity (only one can be NULL)
276 * @param name the name of an identity (only one can be NULL)
277 * @return EgoEntry or NULL if not found
278 */
279struct EgoEntry*
280get_egoentry(struct RequestHandle *handle, char* pubkey, char *name)
281{
282 struct EgoEntry *ego_entry;
283 if (NULL != pubkey)
284 {
285 for (ego_entry = handle->ego_head;
286 NULL != ego_entry;
287 ego_entry = ego_entry->next)
288 {
289 if (0 != strcasecmp (pubkey, ego_entry->keystring))
290 continue;
291 return ego_entry;
292 }
293 }
294 if (NULL != name)
295 {
296 for (ego_entry = handle->ego_head;
297 NULL != ego_entry;
298 ego_entry = ego_entry->next)
299 {
300 if (0 != strcasecmp (name, ego_entry->identifier))
301 continue;
302 return ego_entry;
303 }
304 }
305 return NULL;
306}
307
308
309/**
310 * Callback for GET Request with subsystem
311 *
312 * @param cls the RequestHandle
313 * @param ego the Ego found
314 * @param ctx the context
315 * @param name the id of the ego
316 */
317static void
318ego_get_for_subsystem (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx,
319 const char *name)
320{
321 struct RequestHandle *handle = cls;
322 struct MHD_Response *resp;
323 struct GNUNET_CRYPTO_EcdsaPublicKey public_key;
324 json_t *json_root;
325 char *result_str;
326 char *public_key_string;
327
328 if(NULL == ego)
329 {
330 handle->emsg = GNUNET_strdup("No identity found for subsystem");
331 GNUNET_SCHEDULER_add_now (&do_error, handle);
332 return;
333 }
334
335 GNUNET_IDENTITY_ego_get_public_key(ego,&public_key);
336 public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string(&public_key);
337
338 // create json with subsystem identity
339 json_root = json_object ();
340 json_object_set_new (json_root, GNUNET_REST_PARAM_PUBKEY, json_string(public_key_string));
341 json_object_set_new (json_root, GNUNET_REST_PARAM_NAME, json_string(name));
342
343 result_str = json_dumps (json_root, 0);
344 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
345 resp = GNUNET_REST_create_response (result_str);
346
347 json_decref (json_root);
348 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
349 GNUNET_free(result_str);
350 GNUNET_free(public_key_string);
351 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
352}
353
354/**
355 * Handle identity GET request
356 *
357 * @param con_handle the connection handle
358 * @param url the url
359 * @param cls the RequestHandle
360 */
361void
362ego_get (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
363 void *cls)
364{
365 struct RequestHandle *handle = cls;
366 struct EgoEntry *ego_entry;
367 struct GNUNET_HashCode key;
368 struct MHD_Response *resp;
369 char *keystring;
370 char *egoname;
371 json_t *json_root;
372 json_t *json_ego;
373 char *result_str;
374
375 //requested default identity of subsystem
376 GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_SUBSYSTEM,
377 strlen (GNUNET_REST_PARAM_SUBSYSTEM), &key);
378 if ( GNUNET_YES
379 == GNUNET_CONTAINER_multihashmap_contains (
380 handle->rest_handle->url_param_map, &key))
381 {
382 handle->subsystem = GNUNET_strdup(
383 GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
384 &key));
385 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n",
386 handle->subsystem);
387
388 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
389 handle->subsystem,
390 &ego_get_for_subsystem,
391 handle);
392 if (NULL == handle->op)
393 {
394 handle->emsg = GNUNET_strdup("No identity found for subsystem");
395 GNUNET_SCHEDULER_add_now (&do_error, handle);
396 return;
397 }
398 return;
399 }
400 egoname = NULL;
401 keystring = NULL;
402
403 //one identity requested with key
404 GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_PUBKEY,
405 strlen (GNUNET_REST_PARAM_PUBKEY),
406 &key);
407 if ( GNUNET_YES
408 == GNUNET_CONTAINER_multihashmap_contains (
409 handle->rest_handle->url_param_map, &key))
410 {
411 keystring = GNUNET_CONTAINER_multihashmap_get (
412 handle->rest_handle->url_param_map, &key);
413
414 ego_entry = get_egoentry(handle, keystring, NULL);
415 if (NULL == ego_entry)
416 {
417 handle->emsg = GNUNET_strdup("No identity found for public key");
418 GNUNET_SCHEDULER_add_now (&do_error, handle);
419 return;
420 }
421 egoname = ego_entry->identifier;
422 }
423
424 //one identity requested with name
425 if (NULL == egoname)
426 {
427 GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_NAME,
428 strlen (GNUNET_REST_PARAM_NAME),
429 &key);
430 if ( GNUNET_YES
431 == GNUNET_CONTAINER_multihashmap_contains (
432 handle->rest_handle->url_param_map, &key))
433 {
434 egoname = GNUNET_CONTAINER_multihashmap_get (
435 handle->rest_handle->url_param_map, &key);
436 if (0 >= strlen(egoname))
437 {
438 handle->emsg = GNUNET_strdup("No identity found for name");
439 GNUNET_SCHEDULER_add_now (&do_error, handle);
440 return;
441 }
442 //LOWERCASE ego names?
443 GNUNET_STRINGS_utf8_tolower(egoname, egoname);
444 }
445 }
446
447 json_root = json_array ();
448 //Return ego/egos
449 for (ego_entry = handle->ego_head;
450 NULL != ego_entry; ego_entry = ego_entry->next)
451 {
452 //if only one ego requested
453 if ((NULL != egoname)){
454 if(0 != strcmp (egoname, ego_entry->identifier)){
455 continue;
456 }
457 }
458
459 json_ego = json_object ();
460 json_object_set_new (json_ego,
461 GNUNET_REST_PARAM_PUBKEY,
462 json_string (ego_entry->keystring));
463 json_object_set_new (json_ego,
464 GNUNET_REST_PARAM_NAME,
465 json_string (ego_entry->identifier));
466 json_array_append (json_root, json_ego);
467 json_decref (json_ego);
468 }
469
470 if ((size_t) 0 == json_array_size (json_root))
471 {
472 json_decref (json_root);
473 handle->emsg = GNUNET_strdup("No identities found!");
474 GNUNET_SCHEDULER_add_now (&do_error, handle);
475 return;
476 }
477
478 result_str = json_dumps (json_root, 0);
479 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
480 resp = GNUNET_REST_create_response (result_str);
481
482 json_decref (json_root);
483 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
484 GNUNET_free(result_str);
485 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
486}
487
488
489/**
490 * Processing finished
491 *
492 * @param cls request handle
493 * @param emsg error message
494 */
495static void
496do_finished (void *cls, const char *emsg)
497{
498 struct RequestHandle *handle = cls;
499 struct MHD_Response *resp;
500
501 handle->op = NULL;
502 if (NULL != emsg)
503 {
504 handle->emsg = GNUNET_strdup(emsg);
505 GNUNET_SCHEDULER_add_now (&do_error, handle);
506 return;
507 }
508 resp = GNUNET_REST_create_response (NULL);
509 handle->proc (handle->proc_cls, resp, handle->response_code);
510 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
511}
512
513
514/**
515 * Handle identity PUT request
516 *
517 * @param con_handle the connection handle
518 * @param url the url
519 * @param cls the RequestHandle
520 */
521void
522ego_edit (struct GNUNET_REST_RequestHandle *con_handle,
523 const char* url,
524 void *cls)
525{
526 struct RequestHandle *handle = cls;
527 struct EgoEntry *ego_entry;
528 struct EgoEntry *ego_entry_tmp;
529 struct MHD_Response *resp;
530 int json_state;
531 json_t *data_js;
532 json_error_t err;
533 char *pubkey;
534 char *name;
535 char *newsubsys;
536 char *newname;
537 char term_data[handle->data_size + 1];
538
539 //if no data
540 if (0 >= handle->data_size)
541 {
542 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
543 GNUNET_SCHEDULER_add_now (&do_error, handle);
544 return;
545 }
546 //if not json
547 term_data[handle->data_size] = '\0';
548 GNUNET_memcpy(term_data, handle->data, handle->data_size);
549 data_js = json_loads (term_data,JSON_DECODE_ANY,&err);
550
551 if (NULL == data_js)
552 {
553 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
554 GNUNET_SCHEDULER_add_now (&do_error, handle);
555 return;
556 }
557
558 ego_entry = NULL;
559 pubkey = NULL;
560 name = NULL;
561 newname = NULL;
562 //NEW NAME
563 json_state = 0;
564 json_state = json_unpack(data_js,
565 "{s:s,s?:s,s?:s}",
566 GNUNET_REST_PARAM_NEWNAME,
567 &newname,
568 GNUNET_REST_PARAM_PUBKEY,
569 &pubkey,
570 GNUNET_REST_PARAM_NAME,
571 &name);
572 //Change name with pubkey or name identifier
573 if (0 == json_state)
574 {
575 if (NULL == newname)
576 {
577 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
578 GNUNET_SCHEDULER_add_now (&do_error, handle);
579 json_decref (data_js);
580 return;
581 }
582
583 if (0 >= strlen(newname))
584 {
585 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
586 GNUNET_SCHEDULER_add_now (&do_error, handle);
587 json_decref (data_js);
588 return;
589 }
590 //lower case name
591 GNUNET_STRINGS_utf8_tolower(newname,newname);
592
593 ego_entry = get_egoentry(handle,pubkey,name);
594
595 if (NULL == ego_entry)
596 {
597 resp = GNUNET_REST_create_response (NULL);
598 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
599 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
600 json_decref (data_js);
601 return;
602 }
603
604 for (ego_entry_tmp = handle->ego_head;
605 NULL != ego_entry_tmp; ego_entry_tmp = ego_entry_tmp->next)
606 {
607 if (0 == strcasecmp (newname, ego_entry_tmp->identifier))
608 {
609 //Ego with same name not allowed
610 resp = GNUNET_REST_create_response (NULL);
611 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
612 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
613 json_decref (data_js);
614 return;
615 }
616 }
617 handle->response_code = MHD_HTTP_NO_CONTENT;
618 handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
619 ego_entry->identifier, newname,
620 &do_finished, handle);
621 json_decref (data_js);
622 return;
623 }
624
625 newsubsys = NULL;
626 //SUBSYSTEM
627 json_state = 0;
628 json_state = json_unpack(data_js,
629 "{s:s,s?:s,s?:s}",
630 GNUNET_REST_PARAM_SUBSYSTEM,
631 &newsubsys,
632 GNUNET_REST_PARAM_PUBKEY,
633 &pubkey,
634 GNUNET_REST_PARAM_NAME,
635 &name);
636 //Change subsystem with pubkey or name identifier
637 if (0 == json_state)
638 {
639 if (NULL == newsubsys || (NULL == pubkey && NULL == name))
640 {
641 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
642 GNUNET_SCHEDULER_add_now (&do_error, handle);
643 json_decref (data_js);
644 return;
645 }
646
647 if (0 >= strlen(newsubsys))
648 {
649 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
650 GNUNET_SCHEDULER_add_now (&do_error, handle);
651 json_decref (data_js);
652 return;
653 }
654
655 ego_entry = get_egoentry(handle, pubkey, name);
656
657 if (NULL == ego_entry)
658 {
659 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
660 GNUNET_SCHEDULER_add_now (&do_error, handle);
661 json_decref (data_js);
662 return;
663 }
664
665 handle->response_code = MHD_HTTP_NO_CONTENT;
666 handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
667 newsubsys,
668 ego_entry->ego,
669 &do_finished,
670 handle);
671 json_decref (data_js);
672 return;
673 }
674
675 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
676 GNUNET_SCHEDULER_add_now (&do_error, handle);
677 json_decref (data_js);
678 return;
679}
680
681/**
682 * Handle identity POST request
683 *
684 * @param con_handle the connection handle
685 * @param url the url
686 * @param cls the RequestHandle
687 */
688void
689ego_create (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
690 void *cls)
691{
692 struct RequestHandle *handle = cls;
693 struct EgoEntry *ego_entry;
694 struct MHD_Response *resp;
695 json_t *data_js;
696 json_error_t err;
697 char* egoname;
698 int json_unpack_state;
699 char term_data[handle->data_size + 1];
700
701 if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
702 {
703 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_RESOURCE_INVALID);
704 GNUNET_SCHEDULER_add_now (&do_error, handle);
705 return;
706 }
707
708 if (0 >= handle->data_size)
709 {
710 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
711 GNUNET_SCHEDULER_add_now (&do_error, handle);
712 return;
713 }
714 term_data[handle->data_size] = '\0';
715 GNUNET_memcpy(term_data, handle->data, handle->data_size);
716 data_js = json_loads (term_data,
717 JSON_DECODE_ANY,
718 &err);
719 if (NULL == data_js)
720 {
721 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
722 GNUNET_SCHEDULER_add_now (&do_error, handle);
723 json_decref (data_js);
724 return;
725 }
726 json_unpack_state = 0;
727 json_unpack_state = json_unpack(data_js,
728 "{s:s!}",
729 GNUNET_REST_PARAM_NAME,
730 &egoname);
731 if (0 != json_unpack_state)
732 {
733 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
734 GNUNET_SCHEDULER_add_now (&do_error, handle);
735 json_decref (data_js);
736 return;
737 }
738
739 if (NULL == egoname)
740 {
741 handle->emsg = GNUNET_strdup("No name provided");
742 GNUNET_SCHEDULER_add_now (&do_error, handle);
743 json_decref (data_js);
744 return;
745 }
746 if (0 >= strlen (egoname))
747 {
748 json_decref (data_js);
749 handle->emsg = GNUNET_strdup("No name provided");
750 GNUNET_SCHEDULER_add_now (&do_error, handle);
751 return;
752 }
753 GNUNET_STRINGS_utf8_tolower(egoname, egoname);
754 for (ego_entry = handle->ego_head;
755 NULL != ego_entry; ego_entry = ego_entry->next)
756 {
757 if (0 == strcasecmp (egoname, ego_entry->identifier))
758 {
759 resp = GNUNET_REST_create_response (NULL);
760 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
761 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
762 json_decref (data_js);
763 return;
764 }
765 }
766 handle->name = GNUNET_strdup(egoname);
767 json_decref (data_js);
768 handle->response_code = MHD_HTTP_CREATED;
769 handle->op = GNUNET_IDENTITY_create (handle->identity_handle, handle->name,
770 &do_finished, handle);
771}
772
773/**
774 * Handle identity DELETE request
775 *
776 * @param con_handle the connection handle
777 * @param url the url
778 * @param cls the RequestHandle
779 */
780void
781ego_delete (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
782 void *cls)
783{
784 struct RequestHandle *handle = cls;
785 struct EgoEntry *ego_entry;
786 struct GNUNET_HashCode key;
787 struct MHD_Response *resp;
788 const char *keystring;
789 char *egoname;
790 int ego_exists = GNUNET_NO;
791
792 keystring = NULL;
793 egoname = NULL;
794
795 //delete with pubkey
796 GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_PUBKEY,
797 strlen (GNUNET_REST_PARAM_PUBKEY), &key);
798 if ( GNUNET_YES
799 == GNUNET_CONTAINER_multihashmap_contains (
800 handle->rest_handle->url_param_map, &key))
801 {
802 keystring = GNUNET_CONTAINER_multihashmap_get (
803 handle->rest_handle->url_param_map,&key);
804 }
805
806 GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_NAME,
807 strlen (GNUNET_REST_PARAM_NAME), &key);
808 if ( GNUNET_YES
809 == GNUNET_CONTAINER_multihashmap_contains (
810 handle->rest_handle->url_param_map, &key))
811 {
812 egoname = GNUNET_CONTAINER_multihashmap_get (
813 handle->rest_handle->url_param_map, &key);
814 //LOWERCASE ego names?
815 //GNUNET_STRINGS_utf8_tolower(egoname, egoname);
816 }
817
818 if (NULL != keystring)
819 {
820 for (ego_entry = handle->ego_head;
821 NULL != ego_entry; ego_entry = ego_entry->next)
822 {
823 if (0 != strcasecmp (keystring, ego_entry->keystring))
824 continue;
825 ego_exists = GNUNET_YES;
826 break;
827 }
828 }
829 else if (NULL != egoname)
830 {
831 for (ego_entry = handle->ego_head;
832 NULL != ego_entry; ego_entry = ego_entry->next)
833 {
834 if (0 != strcmp (egoname, ego_entry->identifier))
835 continue;
836 ego_exists = GNUNET_YES;
837 break;
838 }
839 }
840 else
841 {
842 handle->emsg = GNUNET_strdup("Missing parameter pubkey or name");
843 GNUNET_SCHEDULER_add_now (&do_error, handle);
844 return;
845 }
846
847 if (GNUNET_NO == ego_exists)
848 {
849 resp = GNUNET_REST_create_response (NULL);
850 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
851 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
852 return;
853 }
854 handle->response_code = MHD_HTTP_NO_CONTENT;
855 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
856 ego_entry->identifier, &do_finished,
857 handle);
858
859}
860
861/**
862 * Respond to OPTIONS request
863 *
864 * @param con_handle the connection handle
865 * @param url the url
866 * @param cls the RequestHandle
867 */
868static void
869options_cont (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
870 void *cls)
871{
872 struct MHD_Response *resp;
873 struct RequestHandle *handle = cls;
874
875 //For now, independent of path return all options
876 resp = GNUNET_REST_create_response (NULL);
877 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
878 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
879 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
880 return;
881}
882
883/**
884 * Handle rest request
885 *
886 * @param handle the request handle
887 */
888static void
889init_cont (struct RequestHandle *handle)
890{
891 struct GNUNET_REST_RequestHandlerError err;
892 static const struct GNUNET_REST_RequestHandler handlers[] = {
893 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_get },
894 { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY, &ego_edit },
895 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create },
896 { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY, &ego_delete },
897 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont },
898 GNUNET_REST_HANDLER_END
899 };
900
901 if (GNUNET_NO
902 == GNUNET_REST_handle_request (handle->rest_handle, handlers, &err,
903 handle))
904 {
905 handle->response_code = err.error_code;
906 GNUNET_SCHEDULER_add_now (&do_error, handle);
907 }
908}
909
910/**
911 * If listing is enabled, prints information about the egos.
912 *
913 * This function is initially called for all egos and then again
914 * whenever a ego's identifier changes or if it is deleted. At the
915 * end of the initial pass over all egos, the function is once called
916 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
917 * be invoked in the future or that there was an error.
918 *
919 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
920 * this function is only called ONCE, and 'NULL' being passed in
921 * 'ego' does indicate an error (i.e. name is taken or no default
922 * value is known). If 'ego' is non-NULL and if '*ctx'
923 * is set in those callbacks, the value WILL be passed to a subsequent
924 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
925 * that one was not NULL).
926 *
927 * When an identity is renamed, this function is called with the
928 * (known) ego but the NEW identifier.
929 *
930 * When an identity is deleted, this function is called with the
931 * (known) ego and "NULL" for the 'identifier'. In this case,
932 * the 'ego' is henceforth invalid (and the 'ctx' should also be
933 * cleaned up).
934 *
935 * @param cls closure
936 * @param ego ego handle
937 * @param ctx context for application to store data for this ego
938 * (during the lifetime of this process, initially NULL)
939 * @param identifier identifier assigned by the user for this ego,
940 * NULL if the user just deleted the ego and it
941 * must thus no longer be used
942 */
943static void
944init_egos (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx,
945 const char *identifier)
946{
947 struct RequestHandle *handle = cls;
948 struct EgoEntry *ego_entry;
949 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
950
951 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
952 {
953 handle->state = ID_REST_STATE_POST_INIT;
954 init_cont (handle);
955 return;
956 }
957 if (ID_REST_STATE_INIT == handle->state)
958 {
959 ego_entry = GNUNET_new(struct EgoEntry);
960 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
961 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
962 ego_entry->ego = ego;
963 GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
964 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail,
965 ego_entry);
966 }
967}
968
969/**
970 * Function processing the REST call
971 *
972 * @param method HTTP method
973 * @param url URL of the HTTP request
974 * @param data body of the HTTP request (optional)
975 * @param data_size length of the body
976 * @param proc callback function for the result
977 * @param proc_cls closure for callback function
978 * @return GNUNET_OK if request accepted
979 */
980static void
981rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
982 GNUNET_REST_ResultProcessor proc, void *proc_cls)
983{
984 struct RequestHandle *handle = GNUNET_new(struct RequestHandle);
985
986 handle->response_code = 0;
987 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
988 handle->proc_cls = proc_cls;
989 handle->proc = proc;
990 handle->rest_handle = rest_handle;
991 handle->data = rest_handle->data;
992 handle->data_size = rest_handle->data_size;
993
994 handle->url = GNUNET_strdup(rest_handle->url);
995 if (handle->url[strlen (handle->url) - 1] == '/')
996 handle->url[strlen (handle->url) - 1] = '\0';
997 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
998
999 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &init_egos, handle);
1000
1001 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1002 &do_error, handle);
1003
1004 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1005}
1006
1007/**
1008 * Entry point for the plugin.
1009 *
1010 * @param cls Config info
1011 * @return NULL on error, otherwise the plugin context
1012 */
1013void *
1014libgnunet_plugin_rest_identity_init (void *cls)
1015{
1016 static struct Plugin plugin;
1017 struct GNUNET_REST_Plugin *api;
1018
1019 cfg = cls;
1020 if (NULL != plugin.cfg)
1021 return NULL; /* can only initialize once! */
1022 memset (&plugin, 0, sizeof(struct Plugin));
1023 plugin.cfg = cfg;
1024 api = GNUNET_new(struct GNUNET_REST_Plugin);
1025 api->cls = &plugin;
1026 api->name = GNUNET_REST_API_NS_IDENTITY;
1027 api->process_request = &rest_process_request;
1028 GNUNET_asprintf (&allow_methods, "%s, %s, %s, %s, %s",
1029 MHD_HTTP_METHOD_GET,
1030 MHD_HTTP_METHOD_POST,
1031 MHD_HTTP_METHOD_PUT,
1032 MHD_HTTP_METHOD_DELETE,
1033 MHD_HTTP_METHOD_OPTIONS);
1034
1035 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Identity REST API initialized\n"));
1036 return api;
1037}
1038
1039/**
1040 * Exit point from the plugin.
1041 *
1042 * @param cls the plugin context (as returned by "init")
1043 * @return always NULL
1044 */
1045void *
1046libgnunet_plugin_rest_identity_done (void *cls)
1047{
1048 struct GNUNET_REST_Plugin *api = cls;
1049 struct Plugin *plugin = api->cls;
1050 plugin->cfg = NULL;
1051
1052 GNUNET_free_non_null(allow_methods);
1053 GNUNET_free(api);
1054 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n");
1055 return NULL;
1056}
1057
1058/* end of plugin_rest_identity.c */
1059
diff --git a/src/identity/test_plugin_rest_identity.sh b/src/identity/test_plugin_rest_identity.sh
deleted file mode 100755
index d9377500e..000000000
--- a/src/identity/test_plugin_rest_identity.sh
+++ /dev/null
@@ -1,159 +0,0 @@
1#!/usr/bin/bash
2
3#First, start gnunet-arm and the rest-service.
4#Exit 0 means success, exit 1 means failed test
5
6identity_link="http://localhost:7776/identity"
7wrong_link="http://localhost:7776/identityandmore"
8
9
10curl_get () {
11 #$1 is link
12 #$2 is grep
13 cache="$(curl -v "$1" 2>&1 | grep "$2")"
14 #echo $cache
15 if [ "" == "$cache" ]
16 then
17 exit 1
18 fi
19}
20
21curl_post () {
22 #$1 is link
23 #$2 is data
24 #$3 is grep
25 cache="$(curl -v -X "POST" "$1" --data "$2" 2>&1 | grep "$3")"
26 #echo $cache
27 if [ "" == "$cache" ]
28 then
29 exit 1
30 fi
31}
32
33curl_delete () {
34 #$1 is link
35 #$2 is grep
36 cache="$(curl -v -X "DELETE" "$1" 2>&1 | grep "$2")"
37 #echo $cache
38 if [ "" == "$cache" ]
39 then
40 exit 1
41 fi
42}
43
44curl_put () {
45 #$1 is link
46 #$2 is data
47 #$3 is grep
48 cache="$(curl -v -X "PUT" "$1" --data "$2" 2>&1 | grep "$3")"
49 #echo $cache
50 if [ "" == "$cache" ]
51 then
52 exit 1
53 fi
54}
55
56#Test GET
57test="$(gnunet-identity -d)"
58#if no identity exists
59if [ "" == "$test" ]
60then
61 curl_get "$identity_link" "error"
62 gnunet-identity -C "test_plugin_rest_identity"
63 name="$(gnunet-identity -d | awk 'NR==1{print $1}')"
64 public="$(gnunet-identity -d | awk 'NR==1{print $3}')"
65
66 curl_get "${identity_link}?name=$name" "$public"
67 curl_get "${identity_link}?name=" "error"
68 curl_get "${identity_link}?name=$public" "error"
69
70 curl_get "${identity_link}?pubkey=$public" "$name"
71 curl_get "${identity_link}?pubkey=$name" "error"
72 curl_get "${identity_link}?pubkey=" "error"
73
74 gnunet-identity -D "test_plugin_rest_identity"
75else
76 name="$(gnunet-identity -d | awk 'NR==1{print $1}')"
77 public="$(gnunet-identity -d | awk 'NR==1{print $3}')"
78
79 curl_get "${identity_link}?name=$name" "$public"
80 curl_get "${identity_link}?name=" "error"
81 curl_get "${identity_link}?name=$public" "error"
82
83 curl_get "${identity_link}?pubkey=$public" "$name"
84 curl_get "${identity_link}?pubkey=$name" "error"
85 curl_get "${identity_link}?pubkey=" "error"
86fi
87
88#Test POST
89gnunet-identity -D "test_plugin_rest_identity" > /dev/null 2>&1
90gnunet-identity -D "test_plugin_rest_identity1" > /dev/null 2>&1
91
92curl_post "${identity_link}" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 201 Created"
93curl_post "${identity_link}" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 409"
94curl_post "${identity_link}" '{"name":"Test_plugin_rest_identity"}' "HTTP/1.1 409"
95curl_post "${identity_link}" '{}' "error"
96curl_post "${identity_link}" '' "error"
97curl_post "${identity_link}" '{"name":""}' "error"
98curl_post "${identity_link}" '{"name":123}' "error"
99curl_post "${identity_link}" '{"name":[]}' "error"
100curl_post "${identity_link}" '{"name1":"test_plugin_rest_identity"}' "error"
101curl_post "${identity_link}" '{"other":""}' "error"
102curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1", "other":"test_plugin_rest_identity2"}' "error"
103
104#Test PUT
105name="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $1}')"
106public="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $3}')"
107
108curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":"'$public'"}' "HTTP/1.1 204"
109curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":"'$public'"}' "HTTP/1.1 409"
110curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":"'$public'xx"}' "HTTP/1.1 404"
111curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":""}' "HTTP/1.1 404"
112curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubke":""}' "HTTP/1.1 404"
113curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubke":"","other":"sdfdsf"}' "HTTP/1.1 404"
114curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubke":"","name":"sdfdsf"}' "HTTP/1.1 404"
115curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity","pubke":"","name":"test_plugin_rest_identity1"}' "HTTP/1.1 204"
116curl_put "${identity_link}" '{"newnam":"test_plugin_rest_identity","pubkey":"'$public'"}' "error"
117curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","name":"test_plugin_rest_identity"}' "HTTP/1.1 204"
118curl_put "${identity_link}" '{"newname":"TEST_plugin_rest_identity1","name":"test_plugin_rest_identity1"}' "HTTP/1.1 409"
119curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","name":"test_plugin_rest_identity1"}' "HTTP/1.1 409"
120curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity","name":"test_plugin_rest_identityxxx"}' "HTTP/1.1 404"
121curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity","name":"test_plugin_rest_identity1"}' "HTTP/1.1 204"
122curl_put "${identity_link}" '{"newnam":"test_plugin_rest_identityfail","name":"test_plugin_rest_identity"}' "error"
123
124
125#Test subsystem
126curl_put "${identity_link}" '{"subsystem":"namestore","name":"test_plugin_rest_identity"}' "HTTP/1.1 204"
127curl_put "${identity_link}" '{"subsystem":"namestore","name":"test_plugin_rest_identity"}' "HTTP/1.1 204"
128curl_get "${identity_link}?subsystem=namestore" "test_plugin_rest_identity"
129curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created"
130public="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $3}')"
131curl_put "${identity_link}" '{"subsystem":"namestore","pubkey":"'"$public"'"}' "HTTP/1.1 204"
132curl_get "${identity_link}?subsystem=namestore" "test_plugin_rest_identity1"
133curl_get "${identity_link}?subsystem=test_plugin_rest_identity_no_subsystem" "error"
134curl_put "${identity_link}" '{"subsystem":"test_plugin_rest_identity_no_subsystem","name":"test_plugin_rest_identity1"}' "HTTP/1.1 204"
135curl_get "${identity_link}?subsystem=test_plugin_rest_identity_no_subsystem" "test_plugin_rest_identity1"
136
137curl_put "${identity_link}" '{"subsyste":"test_plugin_rest_identity_no_subsystem","name":"test_plugin_rest_identity1"}' "error"
138curl_put "${identity_link}" '{"subsystem":"test_plugin_rest_identity_no_subsystem","name":"Test_plugin_rest_identity1"}' "HTTP/1.1 204"
139
140#Test DELETE
141curl_delete "${identity_link}?name=test_plugin_rest_identity" "HTTP/1.1 204"
142curl_get "${identity_link}?name=test_plugin_rest_identity" "error"
143curl_delete "${identity_link}?name=TEST_plugin_rest_identity1" "HTTP/1.1 404"
144curl_delete "${identity_link}?name=test_plugin_rest_identity1" "HTTP/1.1 204"
145curl_get "${identity_link}?name=test_plugin_rest_identity1" "error"
146curl_delete "${identity_link}?name=test_plugin_rest_identity_not_found" "HTTP/1.1 404"
147curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created"
148public="$(gnunet-identity -d | grep "test_plugin_rest_identity1" | awk 'NR==1{print $3}')"
149curl_delete "${identity_link}?pubkey=$public" "HTTP/1.1 204"
150curl_delete "${identity_link}?pubke=$public" "error"
151curl_delete "${identity_link}?pubkey=$public&other=232" "HTTP/1.1 404"
152
153#Test wrong_link
154curl_get "$wrong_link" "HTTP/1.1 404"
155curl_post "$wrong_link" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 404"
156curl_put "$wrong_link" '{"newname":"test_plugin_rest_identity1","name":"test_plugin_rest_identity"}' "HTTP/1.1 404"
157curl_delete "$wrong_link?name=test_plugin_rest_identity1" "HTTP/1.1 404"
158
159exit 0;