aboutsummaryrefslogtreecommitdiff
path: root/src/identity
diff options
context:
space:
mode:
authorSchanzenbach, Martin <mschanzenbach@posteo.de>2019-03-12 09:39:06 +0100
committerSchanzenbach, Martin <mschanzenbach@posteo.de>2019-03-12 09:39:06 +0100
commit235833535763682224d09a9b0e73fdd09657d7fc (patch)
treecc242dc7b225f98258635df79a37603cdecb9bb4 /src/identity
parent919bb8c92fa1b7cda53401ff2286b980ca0b12d8 (diff)
downloadgnunet-235833535763682224d09a9b0e73fdd09657d7fc.tar.gz
gnunet-235833535763682224d09a9b0e73fdd09657d7fc.zip
move identity rest plugin
Diffstat (limited to 'src/identity')
-rw-r--r--src/identity/Makefile.am21
-rw-r--r--src/identity/plugin_rest_identity.c1321
2 files changed, 1341 insertions, 1 deletions
diff --git a/src/identity/Makefile.am b/src/identity/Makefile.am
index 1f21fc65d..5c1af8e19 100644
--- a/src/identity/Makefile.am
+++ b/src/identity/Makefile.am
@@ -12,6 +12,12 @@ if USE_COVERAGE
12 XLIB = -lgcov 12 XLIB = -lgcov
13endif 13endif
14 14
15if HAVE_MHD
16if HAVE_JSON
17REST_PLUGIN = libgnunet_plugin_rest_identity.la
18endif
19endif
20
15pkgcfgdir= $(pkgdatadir)/config.d/ 21pkgcfgdir= $(pkgdatadir)/config.d/
16 22
17libexecdir= $(pkglibdir)/libexec/ 23libexecdir= $(pkglibdir)/libexec/
@@ -20,7 +26,20 @@ pkgcfg_DATA = \
20 identity.conf 26 identity.conf
21 27
22lib_LTLIBRARIES = \ 28lib_LTLIBRARIES = \
23 libgnunetidentity.la 29 libgnunetidentity.la \
30 $(REST_PLUGIN)
31
32
33libgnunet_plugin_rest_identity_la_SOURCES = \
34 plugin_rest_identity.c
35libgnunet_plugin_rest_identity_la_LIBADD = \
36 libgnunetidentity.la \
37 $(top_builddir)/src/rest/libgnunetrest.la \
38 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
39 $(LTLIBINTL) -ljansson -lmicrohttpd
40libgnunet_plugin_rest_identity_la_LDFLAGS = \
41 $(GN_PLUGIN_LDFLAGS)
42
24 43
25libgnunetidentity_la_SOURCES = \ 44libgnunetidentity_la_SOURCES = \
26 identity_api.c \ 45 identity_api.c \
diff --git a/src/identity/plugin_rest_identity.c b/src/identity/plugin_rest_identity.c
new file mode 100644
index 000000000..3bfca3121
--- /dev/null
+++ b/src/identity/plugin_rest_identity.c
@@ -0,0 +1,1321 @@
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 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Martin Schanzenbach
22 * @author Philippe Buschmann
23 * @file identity/plugin_rest_identity.c
24 * @brief GNUnet Identity REST plugin
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
34/**
35 * Identity Namespace
36 */
37#define GNUNET_REST_API_NS_IDENTITY "/identity"
38
39/**
40 * Identity Namespace with public key specifier
41 */
42#define GNUNET_REST_API_NS_IDENTITY_ALL "/identity/all"
43
44/**
45 * Identity Namespace with public key specifier
46 */
47#define GNUNET_REST_API_NS_IDENTITY_PUBKEY "/identity/pubkey"
48
49/**
50 * Identity Namespace with public key specifier
51 */
52#define GNUNET_REST_API_NS_IDENTITY_NAME "/identity/name"
53
54/**
55 * Identity Subsystem Namespace
56 */
57#define GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM "/identity/subsystem"
58
59/**
60 * Parameter public key
61 */
62#define GNUNET_REST_IDENTITY_PARAM_PUBKEY "pubkey"
63
64/**
65 * Parameter subsystem
66 */
67#define GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM "subsystem"
68
69/**
70 * Parameter name
71 */
72#define GNUNET_REST_IDENTITY_PARAM_NAME "name"
73
74/**
75 * Parameter new name
76 */
77#define GNUNET_REST_IDENTITY_PARAM_NEWNAME "newname"
78
79/**
80 * Error message Unknown Error
81 */
82#define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error"
83
84/**
85 * Error message No identity found
86 */
87#define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found"
88
89/**
90 * Error message Missing identity name
91 */
92#define GNUNET_REST_IDENTITY_MISSING_NAME "Missing identity name"
93
94/**
95 * Error message Missing identity name
96 */
97#define GNUNET_REST_IDENTITY_MISSING_PUBKEY "Missing identity public key"
98
99/**
100 * Error message No data
101 */
102#define GNUNET_REST_ERROR_NO_DATA "No data"
103
104/**
105 * Error message Data invalid
106 */
107#define GNUNET_REST_ERROR_DATA_INVALID "Data invalid"
108
109/**
110 * State while collecting all egos
111 */
112#define ID_REST_STATE_INIT 0
113
114/**
115 * Done collecting egos
116 */
117#define ID_REST_STATE_POST_INIT 1
118
119/**
120 * The configuration handle
121 */
122const struct GNUNET_CONFIGURATION_Handle *cfg;
123
124/**
125 * HTTP methods allows for this plugin
126 */
127static char* allow_methods;
128
129/**
130 * @brief struct returned by the initialization function of the plugin
131 */
132struct Plugin
133{
134 const struct GNUNET_CONFIGURATION_Handle *cfg;
135};
136
137/**
138 * The ego list
139 */
140struct EgoEntry
141{
142 /**
143 * DLL
144 */
145 struct EgoEntry *next;
146
147 /**
148 * DLL
149 */
150 struct EgoEntry *prev;
151
152 /**
153 * Ego Identifier
154 */
155 char *identifier;
156
157 /**
158 * Public key string
159 */
160 char *keystring;
161
162 /**
163 * The Ego
164 */
165 struct GNUNET_IDENTITY_Ego *ego;
166};
167
168/**
169 * The request handle
170 */
171struct RequestHandle
172{
173 /**
174 * The data from the REST request
175 */
176 const char* data;
177
178 /**
179 * The name to look up
180 */
181 char *name;
182
183 /**
184 * the length of the REST data
185 */
186 size_t data_size;
187
188
189 /**
190 * Ego list
191 */
192 struct EgoEntry *ego_head;
193
194 /**
195 * Ego list
196 */
197 struct EgoEntry *ego_tail;
198
199 /**
200 * The processing state
201 */
202 int state;
203
204 /**
205 * Handle to Identity service.
206 */
207 struct GNUNET_IDENTITY_Handle *identity_handle;
208
209 /**
210 * IDENTITY Operation
211 */
212 struct GNUNET_IDENTITY_Operation *op;
213
214 /**
215 * Rest connection
216 */
217 struct GNUNET_REST_RequestHandle *rest_handle;
218
219 /**
220 * Desired timeout for the lookup (default is no timeout).
221 */
222 struct GNUNET_TIME_Relative timeout;
223
224 /**
225 * ID of a task associated with the resolution process.
226 */
227 struct GNUNET_SCHEDULER_Task *timeout_task;
228
229 /**
230 * The plugin result processor
231 */
232 GNUNET_REST_ResultProcessor proc;
233
234 /**
235 * The closure of the result processor
236 */
237 void *proc_cls;
238
239 /**
240 * The url
241 */
242 char *url;
243
244 /**
245 * Error response message
246 */
247 char *emsg;
248
249 /**
250 * Response code
251 */
252 int response_code;
253
254};
255
256/**
257 * Cleanup lookup handle
258 * @param handle Handle to clean up
259 */
260static void
261cleanup_handle (void *cls)
262{
263 struct RequestHandle *handle = cls;
264 struct EgoEntry *ego_entry;
265 struct EgoEntry *ego_tmp;
266
267 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
268 if (NULL != handle->timeout_task)
269 {
270 GNUNET_SCHEDULER_cancel (handle->timeout_task);
271 handle->timeout_task = NULL;
272 }
273
274 if (NULL != handle->url)
275 GNUNET_free(handle->url);
276 if (NULL != handle->emsg)
277 GNUNET_free(handle->emsg);
278 if (NULL != handle->name)
279 GNUNET_free (handle->name);
280 if (NULL != handle->identity_handle)
281 GNUNET_IDENTITY_disconnect (handle->identity_handle);
282
283 for (ego_entry = handle->ego_head;
284 NULL != ego_entry;)
285 {
286 ego_tmp = ego_entry;
287 ego_entry = ego_entry->next;
288 GNUNET_free(ego_tmp->identifier);
289 GNUNET_free(ego_tmp->keystring);
290 GNUNET_free(ego_tmp);
291 }
292
293 GNUNET_free(handle);
294}
295
296/**
297 * Task run on errors. Reports an error and cleans up everything.
298 *
299 * @param cls the `struct RequestHandle`
300 */
301static void
302do_error (void *cls)
303{
304 struct RequestHandle *handle = cls;
305 struct MHD_Response *resp;
306 json_t *json_error = json_object();
307 char *response;
308
309 if (NULL == handle->emsg)
310 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_ERROR_UNKNOWN);
311
312 json_object_set_new(json_error,"error", json_string(handle->emsg));
313
314 if (0 == handle->response_code)
315 handle->response_code = MHD_HTTP_OK;
316 response = json_dumps (json_error, 0);
317 resp = GNUNET_REST_create_response (response);
318 handle->proc (handle->proc_cls, resp, handle->response_code);
319 json_decref(json_error);
320 GNUNET_free(response);
321 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
322}
323
324
325
326/**
327 * Get EgoEntry from list with either a public key or a name
328 * If public key and name are not NULL, it returns the public key result first
329 *
330 * @param handle the RequestHandle
331 * @param pubkey the public key of an identity (only one can be NULL)
332 * @param name the name of an identity (only one can be NULL)
333 * @return EgoEntry or NULL if not found
334 */
335struct EgoEntry*
336get_egoentry(struct RequestHandle *handle, char* pubkey, char *name)
337{
338 struct EgoEntry *ego_entry;
339 if (NULL != pubkey)
340 {
341 for (ego_entry = handle->ego_head;
342 NULL != ego_entry;
343 ego_entry = ego_entry->next)
344 {
345 if (0 != strcasecmp (pubkey, ego_entry->keystring))
346 continue;
347 return ego_entry;
348 }
349 }
350 if (NULL != name)
351 {
352 for (ego_entry = handle->ego_head;
353 NULL != ego_entry;
354 ego_entry = ego_entry->next)
355 {
356 if (0 != strcasecmp (name, ego_entry->identifier))
357 continue;
358 return ego_entry;
359 }
360 }
361 return NULL;
362}
363
364
365/**
366 * Callback for GET Request with subsystem
367 *
368 * @param cls the RequestHandle
369 * @param ego the Ego found
370 * @param ctx the context
371 * @param name the id of the ego
372 */
373static void
374ego_get_for_subsystem (void *cls,
375 struct GNUNET_IDENTITY_Ego *ego,
376 void **ctx,
377 const char *name)
378{
379 struct RequestHandle *handle = cls;
380 struct MHD_Response *resp;
381 struct GNUNET_CRYPTO_EcdsaPublicKey public_key;
382 json_t *json_root;
383 char *result_str;
384 char *public_key_string;
385
386 if(NULL == ego)
387 {
388 handle->response_code = MHD_HTTP_NOT_FOUND;
389 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
390 GNUNET_SCHEDULER_add_now (&do_error, handle);
391 return;
392 }
393
394 GNUNET_IDENTITY_ego_get_public_key(ego,&public_key);
395 public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string(&public_key);
396
397 // create json with subsystem identity
398 json_root = json_object ();
399 json_object_set_new (json_root,
400 GNUNET_REST_IDENTITY_PARAM_PUBKEY,
401 json_string(public_key_string));
402 json_object_set_new (json_root,
403 GNUNET_REST_IDENTITY_PARAM_NAME,
404 json_string(name));
405
406 result_str = json_dumps (json_root, 0);
407 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
408 resp = GNUNET_REST_create_response (result_str);
409
410 json_decref (json_root);
411 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
412 GNUNET_free(result_str);
413 GNUNET_free(public_key_string);
414 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
415}
416
417/**
418 * Handle identity GET request for subsystem
419 *
420 * @param con_handle the connection handle
421 * @param url the url
422 * @param cls the RequestHandle
423 */
424void
425ego_get_subsystem (struct GNUNET_REST_RequestHandle *con_handle,
426 const char* url,
427 void *cls)
428{
429 struct RequestHandle *handle = cls;
430 char *subsystem;
431
432 if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url))
433 {
434 handle->emsg = GNUNET_strdup("Missing subsystem name");
435 GNUNET_SCHEDULER_add_now (&do_error, handle);
436 return;
437 }
438 subsystem = &handle->url[strlen (
439 GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) + 1];
440 //requested default identity of subsystem
441 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsystem);
442
443 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
444 subsystem,
445 &ego_get_for_subsystem,
446 handle);
447
448 if (NULL == handle->op)
449 {
450 handle->response_code = MHD_HTTP_NOT_FOUND;
451 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
452 GNUNET_SCHEDULER_add_now (&do_error, handle);
453 return;
454 }
455}
456
457
458/**
459 * Handle identity GET request - responds with all identities
460 *
461 * @param con_handle the connection handle
462 * @param url the url
463 * @param cls the RequestHandle
464 */
465void
466ego_get_all (struct GNUNET_REST_RequestHandle *con_handle,
467 const char* url,
468 void *cls)
469{
470 struct RequestHandle *handle = cls;
471 struct EgoEntry *ego_entry;
472 struct MHD_Response *resp;
473 json_t *json_root;
474 json_t *json_ego;
475 char *result_str;
476
477 json_root = json_array ();
478 //Return ego/egos
479 for (ego_entry = handle->ego_head;
480 NULL != ego_entry; ego_entry = ego_entry->next)
481 {
482 json_ego = json_object ();
483 json_object_set_new (json_ego,
484 GNUNET_REST_IDENTITY_PARAM_PUBKEY,
485 json_string (ego_entry->keystring));
486 json_object_set_new (json_ego,
487 GNUNET_REST_IDENTITY_PARAM_NAME,
488 json_string (ego_entry->identifier));
489 json_array_append (json_root, json_ego);
490 json_decref (json_ego);
491 }
492
493 if ((size_t) 0 == json_array_size (json_root))
494 {
495 json_decref (json_root);
496 handle->response_code = MHD_HTTP_NOT_FOUND;
497 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
498 GNUNET_SCHEDULER_add_now (&do_error, handle);
499 return;
500 }
501
502 result_str = json_dumps (json_root, 0);
503 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
504 resp = GNUNET_REST_create_response (result_str);
505
506 json_decref (json_root);
507 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
508 GNUNET_free(result_str);
509 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
510}
511
512
513/**
514 * Responds with the ego_entry identity
515 *
516 * @param handle the struct RequestHandle
517 * @param ego_entry the struct EgoEntry for the response
518 */
519void
520ego_get_response (struct RequestHandle *handle, struct EgoEntry *ego_entry)
521{
522 struct MHD_Response *resp;
523 json_t *json_ego;
524 char *result_str;
525
526 json_ego = json_object ();
527 json_object_set_new (json_ego,
528 GNUNET_REST_IDENTITY_PARAM_PUBKEY,
529 json_string (ego_entry->keystring));
530 json_object_set_new (json_ego,
531 GNUNET_REST_IDENTITY_PARAM_NAME,
532 json_string (ego_entry->identifier));
533
534 result_str = json_dumps (json_ego, 0);
535 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
536 resp = GNUNET_REST_create_response (result_str);
537 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
538
539 json_decref (json_ego);
540 GNUNET_free(result_str);
541 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
542}
543
544
545/**
546 * Handle identity GET request with a public key
547 *
548 * @param con_handle the connection handle
549 * @param url the url
550 * @param cls the RequestHandle
551 */
552void
553ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
554 const char* url,
555 void *cls)
556{
557 struct RequestHandle *handle = cls;
558 struct EgoEntry *ego_entry;
559 char *keystring;
560
561 keystring = NULL;
562
563 if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
564 {
565 handle->response_code = MHD_HTTP_NOT_FOUND;
566 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY);
567 GNUNET_SCHEDULER_add_now (&do_error, handle);
568 return;
569 }
570 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1];
571 ego_entry = get_egoentry(handle, keystring, NULL);
572
573 if (NULL == ego_entry)
574 {
575 handle->response_code = MHD_HTTP_NOT_FOUND;
576 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
577 GNUNET_SCHEDULER_add_now (&do_error, handle);
578 return;
579 }
580
581 ego_get_response(handle, ego_entry);
582}
583
584/**
585 * Handle identity GET request with a name
586 *
587 * @param con_handle the connection handle
588 * @param url the url
589 * @param cls the RequestHandle
590 */
591void
592ego_get_name (struct GNUNET_REST_RequestHandle *con_handle,
593 const char* url,
594 void *cls)
595{
596 struct RequestHandle *handle = cls;
597 struct EgoEntry *ego_entry;
598 char *egoname;
599
600 egoname = NULL;
601
602 if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
603 {
604 handle->response_code = MHD_HTTP_NOT_FOUND;
605 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME);
606 GNUNET_SCHEDULER_add_now (&do_error, handle);
607 return;
608 }
609 egoname = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1];
610 ego_entry = get_egoentry(handle, NULL, egoname);
611
612 if (NULL == ego_entry)
613 {
614 handle->response_code = MHD_HTTP_NOT_FOUND;
615 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
616 GNUNET_SCHEDULER_add_now (&do_error, handle);
617 return;
618 }
619
620 ego_get_response(handle, ego_entry);
621}
622
623
624/**
625 * Processing finished
626 *
627 * @param cls request handle
628 * @param emsg error message
629 */
630static void
631do_finished (void *cls, const char *emsg)
632{
633 struct RequestHandle *handle = cls;
634 struct MHD_Response *resp;
635
636 handle->op = NULL;
637 if (NULL != emsg)
638 {
639 handle->emsg = GNUNET_strdup(emsg);
640 GNUNET_SCHEDULER_add_now (&do_error, handle);
641 return;
642 }
643 if (0 == handle->response_code)
644 {
645 handle->response_code = MHD_HTTP_NO_CONTENT;
646 }
647 resp = GNUNET_REST_create_response (NULL);
648 handle->proc (handle->proc_cls, resp, handle->response_code);
649 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
650}
651
652
653/**
654 * Processing edit ego with EgoEntry ego_entry
655 *
656 * @param handle the struct RequestHandle
657 * @param ego_entry the struct EgoEntry we want to edit
658 */
659void
660ego_edit (struct RequestHandle *handle, struct EgoEntry *ego_entry)
661{
662 struct EgoEntry *ego_entry_tmp;
663 struct MHD_Response *resp;
664 json_t *data_js;
665 json_error_t err;
666 char *newname;
667 char term_data[handle->data_size + 1];
668 int json_state;
669
670 //if no data
671 if (0 >= handle->data_size)
672 {
673 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
674 GNUNET_SCHEDULER_add_now (&do_error, handle);
675 return;
676 }
677 //if not json
678 term_data[handle->data_size] = '\0';
679 GNUNET_memcpy(term_data, handle->data, handle->data_size);
680 data_js = json_loads (term_data,JSON_DECODE_ANY,&err);
681
682 if (NULL == data_js)
683 {
684 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
685 GNUNET_SCHEDULER_add_now (&do_error, handle);
686 return;
687 }
688
689 newname = NULL;
690 //NEW NAME
691 json_state = 0;
692 json_state = json_unpack(data_js,
693 "{s:s!}",
694 GNUNET_REST_IDENTITY_PARAM_NEWNAME,
695 &newname);
696 //Change name with pubkey or name identifier
697 if (0 != json_state)
698 {
699
700 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
701 GNUNET_SCHEDULER_add_now (&do_error, handle);
702 json_decref (data_js);
703 return;
704 }
705
706 if (NULL == newname)
707 {
708 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
709 GNUNET_SCHEDULER_add_now (&do_error, handle);
710 json_decref (data_js);
711 return;
712 }
713
714 if (0 >= strlen (newname))
715 {
716 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
717 GNUNET_SCHEDULER_add_now (&do_error, handle);
718 json_decref (data_js);
719 return;
720 }
721
722 ego_entry_tmp = get_egoentry (handle, NULL, newname);
723 if (NULL != ego_entry_tmp)
724 {
725 //Ego with same name not allowed (even if its the ego we change)
726 resp = GNUNET_REST_create_response (NULL);
727 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
728 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
729 json_decref (data_js);
730 return;
731 }
732 handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
733 ego_entry->identifier,
734 newname,
735 &do_finished,
736 handle);
737 if (NULL == handle->op)
738 {
739 handle->emsg = GNUNET_strdup("Rename failed");
740 GNUNET_SCHEDULER_add_now (&do_error, handle);
741 json_decref (data_js);
742 return;
743 }
744 json_decref (data_js);
745 return;
746
747}
748
749
750/**
751 * Handle identity PUT request with public key
752 *
753 * @param con_handle the connection handle
754 * @param url the url
755 * @param cls the RequestHandle
756 */
757void
758ego_edit_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
759 const char* url,
760 void *cls)
761{
762 struct RequestHandle *handle = cls;
763 struct EgoEntry *ego_entry;
764 char *keystring;
765
766 keystring = NULL;
767
768 if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
769 {
770 handle->response_code = MHD_HTTP_NOT_FOUND;
771 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY);
772 GNUNET_SCHEDULER_add_now (&do_error, handle);
773 return;
774 }
775 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1];
776 ego_entry = get_egoentry(handle, keystring, NULL);
777
778 if (NULL == ego_entry)
779 {
780 handle->response_code = MHD_HTTP_NOT_FOUND;
781 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
782 GNUNET_SCHEDULER_add_now (&do_error, handle);
783 return;
784 }
785
786 ego_edit(handle,ego_entry);
787}
788
789/**
790 * Handle identity PUT request with name
791 *
792 * @param con_handle the connection handle
793 * @param url the url
794 * @param cls the RequestHandle
795 */
796void
797ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle,
798 const char* url,
799 void *cls)
800{
801 struct RequestHandle *handle = cls;
802 struct EgoEntry *ego_entry;
803 char *name;
804
805 name = NULL;
806
807 if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
808 {
809 handle->response_code = MHD_HTTP_NOT_FOUND;
810 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME);
811 GNUNET_SCHEDULER_add_now (&do_error, handle);
812 return;
813 }
814 name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1];
815 ego_entry = get_egoentry(handle, NULL, name);
816
817 if (NULL == ego_entry)
818 {
819 handle->response_code = MHD_HTTP_NOT_FOUND;
820 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
821 GNUNET_SCHEDULER_add_now (&do_error, handle);
822 return;
823 }
824
825 ego_edit(handle,ego_entry);
826}
827
828/**
829 * Handle identity subsystem PUT request with name
830 *
831 * @param con_handle the connection handle
832 * @param url the url
833 * @param cls the RequestHandle
834 */
835void
836ego_edit_subsystem (struct GNUNET_REST_RequestHandle *con_handle,
837 const char* url,
838 void *cls)
839{
840 struct RequestHandle *handle = cls;
841 struct EgoEntry *ego_entry;
842 json_t *data_js;
843 json_error_t err;
844 char *newsubsys;
845 char *name;
846 char term_data[handle->data_size + 1];
847 int json_state;
848
849 name = NULL;
850
851 if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url))
852 {
853 handle->response_code = MHD_HTTP_NOT_FOUND;
854 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME);
855 GNUNET_SCHEDULER_add_now (&do_error, handle);
856 return;
857 }
858 name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM)+1];
859 ego_entry = get_egoentry(handle, NULL, name);
860
861 if (NULL == ego_entry)
862 {
863 handle->response_code = MHD_HTTP_NOT_FOUND;
864 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
865 GNUNET_SCHEDULER_add_now (&do_error, handle);
866 return;
867 }
868
869 //if no data
870 if (0 >= handle->data_size)
871 {
872 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
873 GNUNET_SCHEDULER_add_now (&do_error, handle);
874 return;
875 }
876 //if not json
877 term_data[handle->data_size] = '\0';
878 GNUNET_memcpy(term_data, handle->data, handle->data_size);
879 data_js = json_loads (term_data,JSON_DECODE_ANY,&err);
880
881 if (NULL == data_js)
882 {
883 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
884 GNUNET_SCHEDULER_add_now (&do_error, handle);
885 return;
886 }
887
888 newsubsys = NULL;
889 //SUBSYSTEM
890 json_state = 0;
891 json_state = json_unpack(data_js,
892 "{s:s!}",
893 GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM,
894 &newsubsys);
895 //Change subsystem with pubkey or name identifier
896 if (0 != json_state)
897 {
898 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
899 GNUNET_SCHEDULER_add_now (&do_error, handle);
900 json_decref (data_js);
901 return;
902 }
903
904 if (NULL == newsubsys)
905 {
906 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
907 GNUNET_SCHEDULER_add_now (&do_error, handle);
908 json_decref (data_js);
909 return;
910 }
911
912 if (0 >= strlen (newsubsys))
913 {
914 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
915 GNUNET_SCHEDULER_add_now (&do_error, handle);
916 json_decref (data_js);
917 return;
918 }
919
920 handle->response_code = MHD_HTTP_NO_CONTENT;
921 handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
922 newsubsys,
923 ego_entry->ego,
924 &do_finished,
925 handle);
926 if (NULL == handle->op)
927 {
928 handle->emsg = GNUNET_strdup("Setting subsystem failed");
929 GNUNET_SCHEDULER_add_now (&do_error, handle);
930 return;
931 }
932 json_decref (data_js);
933 return;
934
935}
936
937/**
938 * Handle identity POST request
939 *
940 * @param con_handle the connection handle
941 * @param url the url
942 * @param cls the RequestHandle
943 */
944void
945ego_create (struct GNUNET_REST_RequestHandle *con_handle,
946 const char* url,
947 void *cls)
948{
949 struct RequestHandle *handle = cls;
950 struct EgoEntry *ego_entry;
951 struct MHD_Response *resp;
952 json_t *data_js;
953 json_error_t err;
954 char* egoname;
955 int json_unpack_state;
956 char term_data[handle->data_size + 1];
957
958 if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
959 {
960 GNUNET_SCHEDULER_add_now (&do_error, handle);
961 return;
962 }
963
964 if (0 >= handle->data_size)
965 {
966 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
967 GNUNET_SCHEDULER_add_now (&do_error, handle);
968 return;
969 }
970 term_data[handle->data_size] = '\0';
971 GNUNET_memcpy(term_data, handle->data, handle->data_size);
972 data_js = json_loads (term_data,
973 JSON_DECODE_ANY,
974 &err);
975 if (NULL == data_js)
976 {
977 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
978 GNUNET_SCHEDULER_add_now (&do_error, handle);
979 json_decref (data_js);
980 return;
981 }
982 json_unpack_state = 0;
983 json_unpack_state = json_unpack(data_js,
984 "{s:s!}",
985 GNUNET_REST_IDENTITY_PARAM_NAME,
986 &egoname);
987 if (0 != json_unpack_state)
988 {
989 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
990 GNUNET_SCHEDULER_add_now (&do_error, handle);
991 json_decref (data_js);
992 return;
993 }
994
995 if (NULL == egoname)
996 {
997 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
998 GNUNET_SCHEDULER_add_now (&do_error, handle);
999 json_decref (data_js);
1000 return;
1001 }
1002 if (0 >= strlen (egoname))
1003 {
1004 json_decref (data_js);
1005 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
1006 GNUNET_SCHEDULER_add_now (&do_error, handle);
1007 return;
1008 }
1009 GNUNET_STRINGS_utf8_tolower(egoname, egoname);
1010 for (ego_entry = handle->ego_head;
1011 NULL != ego_entry; ego_entry = ego_entry->next)
1012 {
1013 if (0 == strcasecmp (egoname, ego_entry->identifier))
1014 {
1015 resp = GNUNET_REST_create_response (NULL);
1016 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
1017 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
1018 json_decref (data_js);
1019 return;
1020 }
1021 }
1022 handle->name = GNUNET_strdup(egoname);
1023 json_decref (data_js);
1024 handle->response_code = MHD_HTTP_CREATED;
1025 handle->op = GNUNET_IDENTITY_create (handle->identity_handle, handle->name,
1026 &do_finished, handle);
1027}
1028
1029/**
1030 * Handle identity DELETE request with public key
1031 *
1032 * @param con_handle the connection handle
1033 * @param url the url
1034 * @param cls the RequestHandle
1035 */
1036void
1037ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
1038 const char* url,
1039 void *cls)
1040{
1041 struct RequestHandle *handle = cls;
1042 struct EgoEntry *ego_entry;
1043 char *keystring;
1044
1045 keystring = NULL;
1046
1047 if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
1048 {
1049 handle->response_code = MHD_HTTP_NOT_FOUND;
1050 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_PUBKEY);
1051 GNUNET_SCHEDULER_add_now (&do_error, handle);
1052 return;
1053 }
1054 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY)+1];
1055 ego_entry = get_egoentry(handle, keystring, NULL);
1056
1057 if (NULL == ego_entry)
1058 {
1059 handle->response_code = MHD_HTTP_NOT_FOUND;
1060 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
1061 GNUNET_SCHEDULER_add_now (&do_error, handle);
1062 return;
1063 }
1064
1065 handle->response_code = MHD_HTTP_NO_CONTENT;
1066 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
1067 ego_entry->identifier,
1068 &do_finished,
1069 handle);
1070}
1071
1072
1073/**
1074 * Handle identity DELETE request with name
1075 *
1076 * @param con_handle the connection handle
1077 * @param url the url
1078 * @param cls the RequestHandle
1079 */
1080void
1081ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle,
1082 const char* url,
1083 void *cls)
1084{
1085 struct RequestHandle *handle = cls;
1086 struct EgoEntry *ego_entry;
1087 char *name;
1088
1089 name = NULL;
1090
1091 if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
1092 {
1093 handle->response_code = MHD_HTTP_NOT_FOUND;
1094 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_MISSING_NAME);
1095 GNUNET_SCHEDULER_add_now (&do_error, handle);
1096 return;
1097 }
1098 name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME)+1];
1099 ego_entry = get_egoentry(handle, NULL, name);
1100
1101 if (NULL == ego_entry)
1102 {
1103 handle->response_code = MHD_HTTP_NOT_FOUND;
1104 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
1105 GNUNET_SCHEDULER_add_now (&do_error, handle);
1106 return;
1107 }
1108
1109 handle->response_code = MHD_HTTP_NO_CONTENT;
1110 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
1111 ego_entry->identifier,
1112 &do_finished,
1113 handle);
1114}
1115
1116
1117/**
1118 * Respond to OPTIONS request
1119 *
1120 * @param con_handle the connection handle
1121 * @param url the url
1122 * @param cls the RequestHandle
1123 */
1124static void
1125options_cont (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
1126 void *cls)
1127{
1128 struct MHD_Response *resp;
1129 struct RequestHandle *handle = cls;
1130
1131 //For now, independent of path return all options
1132 resp = GNUNET_REST_create_response (NULL);
1133 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
1134 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1135 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
1136 return;
1137}
1138
1139/**
1140 * Handle rest request
1141 *
1142 * @param handle the request handle
1143 */
1144static void
1145init_cont (struct RequestHandle *handle)
1146{
1147 struct GNUNET_REST_RequestHandlerError err;
1148 static const struct GNUNET_REST_RequestHandler handlers[] = {
1149 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ALL, &ego_get_all },
1150 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_get_pubkey },
1151 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_get_name },
1152 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_get_subsystem },
1153 { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_edit_pubkey },
1154 { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_edit_name },
1155 { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM, &ego_edit_subsystem },
1156 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create },
1157 { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_PUBKEY, &ego_delete_pubkey },
1158 { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_delete_name },
1159 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont },
1160 GNUNET_REST_HANDLER_END
1161 };
1162
1163 if (GNUNET_NO
1164 == GNUNET_REST_handle_request (handle->rest_handle, handlers, &err,
1165 handle))
1166 {
1167 handle->response_code = err.error_code;
1168 GNUNET_SCHEDULER_add_now (&do_error, handle);
1169 }
1170}
1171
1172/**
1173 * If listing is enabled, prints information about the egos.
1174 *
1175 * This function is initially called for all egos and then again
1176 * whenever a ego's identifier changes or if it is deleted. At the
1177 * end of the initial pass over all egos, the function is once called
1178 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1179 * be invoked in the future or that there was an error.
1180 *
1181 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1182 * this function is only called ONCE, and 'NULL' being passed in
1183 * 'ego' does indicate an error (i.e. name is taken or no default
1184 * value is known). If 'ego' is non-NULL and if '*ctx'
1185 * is set in those callbacks, the value WILL be passed to a subsequent
1186 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1187 * that one was not NULL).
1188 *
1189 * When an identity is renamed, this function is called with the
1190 * (known) ego but the NEW identifier.
1191 *
1192 * When an identity is deleted, this function is called with the
1193 * (known) ego and "NULL" for the 'identifier'. In this case,
1194 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1195 * cleaned up).
1196 *
1197 * @param cls closure
1198 * @param ego ego handle
1199 * @param ctx context for application to store data for this ego
1200 * (during the lifetime of this process, initially NULL)
1201 * @param identifier identifier assigned by the user for this ego,
1202 * NULL if the user just deleted the ego and it
1203 * must thus no longer be used
1204 */
1205static void
1206init_egos (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx,
1207 const char *identifier)
1208{
1209 struct RequestHandle *handle = cls;
1210 struct EgoEntry *ego_entry;
1211 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1212
1213 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1214 {
1215 handle->state = ID_REST_STATE_POST_INIT;
1216 init_cont (handle);
1217 return;
1218 }
1219 if (ID_REST_STATE_INIT == handle->state)
1220 {
1221 ego_entry = GNUNET_new(struct EgoEntry);
1222 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1223 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1224 ego_entry->ego = ego;
1225 GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
1226 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail,
1227 ego_entry);
1228 }
1229}
1230
1231/**
1232 * Function processing the REST call
1233 *
1234 * @param method HTTP method
1235 * @param url URL of the HTTP request
1236 * @param data body of the HTTP request (optional)
1237 * @param data_size length of the body
1238 * @param proc callback function for the result
1239 * @param proc_cls closure for callback function
1240 * @return GNUNET_OK if request accepted
1241 */
1242static void
1243rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1244 GNUNET_REST_ResultProcessor proc, void *proc_cls)
1245{
1246 struct RequestHandle *handle = GNUNET_new(struct RequestHandle);
1247
1248 handle->response_code = 0;
1249 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1250 handle->proc_cls = proc_cls;
1251 handle->proc = proc;
1252 handle->rest_handle = rest_handle;
1253 handle->data = rest_handle->data;
1254 handle->data_size = rest_handle->data_size;
1255
1256 handle->url = GNUNET_strdup(rest_handle->url);
1257 if (handle->url[strlen (handle->url) - 1] == '/')
1258 handle->url[strlen (handle->url) - 1] = '\0';
1259 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1260
1261 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &init_egos, handle);
1262
1263 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1264 &do_error, handle);
1265
1266 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1267}
1268
1269/**
1270 * Entry point for the plugin.
1271 *
1272 * @param cls Config info
1273 * @return NULL on error, otherwise the plugin context
1274 */
1275void *
1276libgnunet_plugin_rest_identity_init (void *cls)
1277{
1278 static struct Plugin plugin;
1279 struct GNUNET_REST_Plugin *api;
1280
1281 cfg = cls;
1282 if (NULL != plugin.cfg)
1283 return NULL; /* can only initialize once! */
1284 memset (&plugin, 0, sizeof(struct Plugin));
1285 plugin.cfg = cfg;
1286 api = GNUNET_new(struct GNUNET_REST_Plugin);
1287 api->cls = &plugin;
1288 api->name = GNUNET_REST_API_NS_IDENTITY;
1289 api->process_request = &rest_process_request;
1290 GNUNET_asprintf (&allow_methods, "%s, %s, %s, %s, %s",
1291 MHD_HTTP_METHOD_GET,
1292 MHD_HTTP_METHOD_POST,
1293 MHD_HTTP_METHOD_PUT,
1294 MHD_HTTP_METHOD_DELETE,
1295 MHD_HTTP_METHOD_OPTIONS);
1296
1297 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Identity REST API initialized\n"));
1298 return api;
1299}
1300
1301/**
1302 * Exit point from the plugin.
1303 *
1304 * @param cls the plugin context (as returned by "init")
1305 * @return always NULL
1306 */
1307void *
1308libgnunet_plugin_rest_identity_done (void *cls)
1309{
1310 struct GNUNET_REST_Plugin *api = cls;
1311 struct Plugin *plugin = api->cls;
1312 plugin->cfg = NULL;
1313
1314 GNUNET_free_non_null(allow_methods);
1315 GNUNET_free(api);
1316 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n");
1317 return NULL;
1318}
1319
1320/* end of plugin_rest_identity.c */
1321