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