aboutsummaryrefslogtreecommitdiff
path: root/src/service/rest/identity_plugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/rest/identity_plugin.c')
-rw-r--r--src/service/rest/identity_plugin.c1287
1 files changed, 1287 insertions, 0 deletions
diff --git a/src/service/rest/identity_plugin.c b/src/service/rest/identity_plugin.c
new file mode 100644
index 000000000..f6c9dd792
--- /dev/null
+++ b/src/service/rest/identity_plugin.c
@@ -0,0 +1,1287 @@
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 *id_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
924
925struct ego_sign_data_cls
926{
927 void *data;
928 struct RequestHandle *handle;
929};
930
931void
932ego_sign_data_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
933{
934 struct RequestHandle *handle = ((struct ego_sign_data_cls *) cls)->handle;
935 unsigned char *data
936 = (unsigned char *) ((struct ego_sign_data_cls *) cls)->data; // data is url decoded
937 struct MHD_Response *resp;
938 struct GNUNET_CRYPTO_EddsaSignature sig;
939 char *sig_str;
940 char *result;
941
942 if (ego == NULL)
943 {
944 handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND;
945 GNUNET_SCHEDULER_add_now (&do_error, handle);
946 return;
947 }
948
949 if (ntohl (ego->pk.type) != GNUNET_PUBLIC_KEY_TYPE_EDDSA)
950 {
951 handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND;
952 GNUNET_SCHEDULER_add_now (&do_error, handle);
953 return;
954 }
955
956 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign_raw (&(ego->pk.eddsa_key),
957 (void *) data,
958 strlen ( (char*) data),
959 &sig))
960 {
961 handle->ec = GNUNET_EC_UNKNOWN;
962 GNUNET_SCHEDULER_add_now (&do_error, handle);
963 return;
964 }
965
966 GNUNET_STRINGS_base64url_encode (&sig,
967 sizeof (struct GNUNET_CRYPTO_EddsaSignature),
968 &sig_str);
969
970 GNUNET_asprintf (&result,
971 "{\"signature\": \"%s\"}",
972 sig_str);
973
974 resp = GNUNET_REST_create_response (result);
975 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
976
977 free (data);
978 free (sig_str);
979 free (result);
980 free (cls);
981 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
982}
983
984
985/**
986 *
987 * @param con_handle the connection handle
988 * @param url the url
989 * @param cls the RequestHandle
990 */
991void
992ego_sign_data (struct GNUNET_REST_RequestHandle *con_handle,
993 const char *url,
994 void *cls)
995{
996 // TODO: replace with precompiler #define
997 const char *username_key = "user";
998 const char *data_key = "data";
999
1000 struct RequestHandle *handle = cls;
1001 struct GNUNET_HashCode cache_key_username;
1002 struct GNUNET_HashCode cache_key_data;
1003 char *username;
1004 char *data;
1005
1006 struct ego_sign_data_cls *cls2;
1007
1008 GNUNET_CRYPTO_hash (username_key, strlen (username_key), &cache_key_username);
1009 GNUNET_CRYPTO_hash (data_key, strlen (data_key), &cache_key_data);
1010
1011 if ((GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (
1012 handle->rest_handle->url_param_map,
1013 &cache_key_username)) ||
1014 (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (
1015 handle->rest_handle->url_param_map,
1016 &cache_key_data)))
1017 {
1018 handle->ec = GNUNET_EC_UNKNOWN;
1019 GNUNET_SCHEDULER_add_now (&do_error, handle);
1020 return;
1021 }
1022
1023 username = (char *) GNUNET_CONTAINER_multihashmap_get (
1024 handle->rest_handle->url_param_map,
1025 &cache_key_username);
1026
1027 data = (char *) GNUNET_CONTAINER_multihashmap_get (
1028 handle->rest_handle->url_param_map,
1029 &cache_key_data);
1030
1031 cls2 = malloc (sizeof(struct ego_sign_data_cls));
1032 cls2->data = (void *) GNUNET_strdup (data);
1033 cls2->handle = handle;
1034
1035 GNUNET_IDENTITY_ego_lookup (id_cfg,
1036 username,
1037 ego_sign_data_cb,
1038 cls2);
1039}
1040
1041
1042/**
1043 * Respond to OPTIONS request
1044 *
1045 * @param con_handle the connection handle
1046 * @param url the url
1047 * @param cls the RequestHandle
1048 */
1049static void
1050options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1051 const char *url,
1052 void *cls)
1053{
1054 struct MHD_Response *resp;
1055 struct RequestHandle *handle = cls;
1056
1057 // For now, independent of path return all options
1058 resp = GNUNET_REST_create_response (NULL);
1059 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
1060 "Access-Control-Allow-Methods",
1061 allow_methods));
1062 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1063 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
1064 return;
1065}
1066
1067
1068static void
1069list_ego (void *cls,
1070 struct GNUNET_IDENTITY_Ego *ego,
1071 void **ctx,
1072 const char *identifier)
1073{
1074 struct EgoEntry *ego_entry;
1075 struct GNUNET_CRYPTO_PublicKey pk;
1076
1077 if ((NULL == ego) && (ID_REST_STATE_INIT == state))
1078 {
1079 state = ID_REST_STATE_POST_INIT;
1080 return;
1081 }
1082 if (NULL == ego)
1083 {
1084 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1085 "Called with NULL ego\n");
1086 return;
1087 }
1088 if (ID_REST_STATE_INIT == state)
1089 {
1090 ego_entry = GNUNET_new (struct EgoEntry);
1091 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1092 ego_entry->keystring = GNUNET_CRYPTO_public_key_to_string (&pk);
1093 ego_entry->ego = ego;
1094 ego_entry->identifier = GNUNET_strdup (identifier);
1095 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
1096 ego_tail,
1097 ego_entry);
1098 }
1099 /* Ego renamed or added */
1100 if (identifier != NULL)
1101 {
1102 for (ego_entry = ego_head; NULL != ego_entry;
1103 ego_entry = ego_entry->next)
1104 {
1105 if (ego_entry->ego == ego)
1106 {
1107 /* Rename */
1108 GNUNET_free (ego_entry->identifier);
1109 ego_entry->identifier = GNUNET_strdup (identifier);
1110 break;
1111 }
1112 }
1113 if (NULL == ego_entry)
1114 {
1115 /* Add */
1116 ego_entry = GNUNET_new (struct EgoEntry);
1117 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1118 ego_entry->keystring = GNUNET_CRYPTO_public_key_to_string (&pk);
1119 ego_entry->ego = ego;
1120 ego_entry->identifier = GNUNET_strdup (identifier);
1121 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
1122 ego_tail,
1123 ego_entry);
1124 }
1125 }
1126 else
1127 {
1128 /* Delete */
1129 for (ego_entry = ego_head; NULL != ego_entry;
1130 ego_entry = ego_entry->next)
1131 {
1132 if (ego_entry->ego == ego)
1133 break;
1134 }
1135 if (NULL == ego_entry)
1136 return; /* Not found */
1137
1138 GNUNET_CONTAINER_DLL_remove (ego_head,
1139 ego_tail,
1140 ego_entry);
1141 GNUNET_free (ego_entry->identifier);
1142 GNUNET_free (ego_entry->keystring);
1143 GNUNET_free (ego_entry);
1144 return;
1145 }
1146
1147}
1148
1149
1150/**
1151 * Function processing the REST call
1152 *
1153 * @param method HTTP method
1154 * @param url URL of the HTTP request
1155 * @param data body of the HTTP request (optional)
1156 * @param data_size length of the body
1157 * @param proc callback function for the result
1158 * @param proc_cls closure for callback function
1159 * @return GNUNET_OK if request accepted
1160 */
1161enum GNUNET_GenericReturnValue
1162REST_identity_process_request (void* plugin,
1163 struct GNUNET_REST_RequestHandle *rest_handle,
1164 GNUNET_REST_ResultProcessor proc,
1165 void *proc_cls)
1166{
1167 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1168 struct GNUNET_REST_RequestHandlerError err;
1169 static const struct GNUNET_REST_RequestHandler handlers[] =
1170 { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PUBKEY,
1171 &ego_get_pubkey },
1172 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_get_name },
1173 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_get_all },
1174 { MHD_HTTP_METHOD_PUT,
1175 GNUNET_REST_API_NS_IDENTITY_PUBKEY,
1176 &ego_edit_pubkey },
1177 { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_edit_name },
1178 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create },
1179 { MHD_HTTP_METHOD_DELETE,
1180 GNUNET_REST_API_NS_IDENTITY_PUBKEY,
1181 &ego_delete_pubkey },
1182 { MHD_HTTP_METHOD_DELETE,
1183 GNUNET_REST_API_NS_IDENTITY_NAME,
1184 &ego_delete_name },
1185 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont },
1186 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_SIGN, &ego_sign_data},
1187 GNUNET_REST_HANDLER_END };
1188
1189
1190 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1191 handle->proc_cls = proc_cls;
1192 handle->proc = proc;
1193 handle->rest_handle = rest_handle;
1194 handle->data = rest_handle->data;
1195 handle->data_size = rest_handle->data_size;
1196
1197 handle->url = GNUNET_strdup (rest_handle->url);
1198 if (handle->url[strlen (handle->url) - 1] == '/')
1199 handle->url[strlen (handle->url) - 1] = '\0';
1200 handle->timeout_task =
1201 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_error, handle);
1202 GNUNET_CONTAINER_DLL_insert (requests_head,
1203 requests_tail,
1204 handle);
1205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1206 if (GNUNET_NO ==
1207 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1208 {
1209 cleanup_handle (handle);
1210 return GNUNET_NO;
1211 }
1212
1213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1214 return GNUNET_YES;
1215}
1216
1217
1218/**
1219 * Entry point for the plugin.
1220 *
1221 * @param cls Config info
1222 * @return NULL on error, otherwise the plugin context
1223 */
1224void *
1225REST_identity_init (const struct GNUNET_CONFIGURATION_Handle *c)
1226{
1227 static struct Plugin plugin;
1228 struct GNUNET_REST_Plugin *api;
1229
1230 id_cfg = c;
1231 if (NULL != plugin.cfg)
1232 return NULL; /* can only initialize once! */
1233 memset (&plugin, 0, sizeof(struct Plugin));
1234 plugin.cfg = c;
1235 api = GNUNET_new (struct GNUNET_REST_Plugin);
1236 api->cls = &plugin;
1237 api->name = GNUNET_REST_API_NS_IDENTITY;
1238 GNUNET_asprintf (&allow_methods,
1239 "%s, %s, %s, %s, %s",
1240 MHD_HTTP_METHOD_GET,
1241 MHD_HTTP_METHOD_POST,
1242 MHD_HTTP_METHOD_PUT,
1243 MHD_HTTP_METHOD_DELETE,
1244 MHD_HTTP_METHOD_OPTIONS);
1245 state = ID_REST_STATE_INIT;
1246 identity_handle = GNUNET_IDENTITY_connect (id_cfg, &list_ego, NULL);
1247
1248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Identity REST API initialized\n"));
1249 return api;
1250}
1251
1252
1253/**
1254 * Exit point from the plugin.
1255 *
1256 * @param cls the plugin context (as returned by "init")
1257 * @return always NULL
1258 */
1259void
1260REST_identity_done (struct GNUNET_REST_Plugin *api)
1261{
1262 struct Plugin *plugin = api->cls;
1263 struct EgoEntry *ego_entry;
1264 struct EgoEntry *ego_tmp;
1265
1266 plugin->cfg = NULL;
1267 while (NULL != requests_head)
1268 cleanup_handle (requests_head);
1269 if (NULL != identity_handle)
1270 GNUNET_IDENTITY_disconnect (identity_handle);
1271
1272 for (ego_entry = ego_head; NULL != ego_entry;)
1273 {
1274 ego_tmp = ego_entry;
1275 ego_entry = ego_entry->next;
1276 GNUNET_free (ego_tmp->identifier);
1277 GNUNET_free (ego_tmp->keystring);
1278 GNUNET_free (ego_tmp);
1279 }
1280
1281 GNUNET_free (allow_methods);
1282 GNUNET_free (api);
1283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n");
1284}
1285
1286
1287/* end of plugin_rest_identity.c */