aboutsummaryrefslogtreecommitdiff
path: root/src/reclaim/plugin_rest_reclaim.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/reclaim/plugin_rest_reclaim.c')
-rw-r--r--src/reclaim/plugin_rest_reclaim.c1104
1 files changed, 1104 insertions, 0 deletions
diff --git a/src/reclaim/plugin_rest_reclaim.c b/src/reclaim/plugin_rest_reclaim.c
new file mode 100644
index 000000000..b36ed2bb6
--- /dev/null
+++ b/src/reclaim/plugin_rest_reclaim.c
@@ -0,0 +1,1104 @@
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 reclaim/plugin_rest_reclaim.c
24 * @brief GNUnet reclaim REST plugin
25 *
26 */
27
28#include "platform.h"
29#include "gnunet_rest_plugin.h"
30#include "gnunet_identity_service.h"
31#include "gnunet_gns_service.h"
32#include "gnunet_gnsrecord_lib.h"
33#include "gnunet_namestore_service.h"
34#include "gnunet_rest_lib.h"
35#include "microhttpd.h"
36#include <jansson.h>
37#include <inttypes.h>
38#include "gnunet_signatures.h"
39#include "gnunet_reclaim_attribute_lib.h"
40#include "gnunet_reclaim_service.h"
41#include "json_reclaim.h"
42
43/**
44 * REST root namespace
45 */
46#define GNUNET_REST_API_NS_RECLAIM "/reclaim"
47
48/**
49 * Attribute namespace
50 */
51#define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/reclaim/attributes"
52
53/**
54 * Ticket namespace
55 */
56#define GNUNET_REST_API_NS_IDENTITY_TICKETS "/reclaim/tickets"
57
58/**
59 * Revoke namespace
60 */
61#define GNUNET_REST_API_NS_IDENTITY_REVOKE "/reclaim/revoke"
62
63/**
64 * Revoke namespace
65 */
66#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/reclaim/consume"
67
68/**
69 * State while collecting all egos
70 */
71#define ID_REST_STATE_INIT 0
72
73/**
74 * Done collecting egos
75 */
76#define ID_REST_STATE_POST_INIT 1
77
78/**
79 * The configuration handle
80 */
81const struct GNUNET_CONFIGURATION_Handle *cfg;
82
83/**
84 * HTTP methods allows for this plugin
85 */
86static char* allow_methods;
87
88/**
89 * @brief struct returned by the initialization function of the plugin
90 */
91struct Plugin
92{
93 const struct GNUNET_CONFIGURATION_Handle *cfg;
94};
95
96/**
97 * The ego list
98 */
99struct EgoEntry
100{
101 /**
102 * DLL
103 */
104 struct EgoEntry *next;
105
106 /**
107 * DLL
108 */
109 struct EgoEntry *prev;
110
111 /**
112 * Ego Identifier
113 */
114 char *identifier;
115
116 /**
117 * Public key string
118 */
119 char *keystring;
120
121 /**
122 * The Ego
123 */
124 struct GNUNET_IDENTITY_Ego *ego;
125};
126
127
128struct RequestHandle
129{
130 /**
131 * Ego list
132 */
133 struct EgoEntry *ego_head;
134
135 /**
136 * Ego list
137 */
138 struct EgoEntry *ego_tail;
139
140 /**
141 * Selected ego
142 */
143 struct EgoEntry *ego_entry;
144
145 /**
146 * Pointer to ego private key
147 */
148 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
149
150 /**
151 * The processing state
152 */
153 int state;
154
155 /**
156 * Handle to Identity service.
157 */
158 struct GNUNET_IDENTITY_Handle *identity_handle;
159
160 /**
161 * Rest connection
162 */
163 struct GNUNET_REST_RequestHandle *rest_handle;
164
165 /**
166 * Handle to NAMESTORE
167 */
168 struct GNUNET_NAMESTORE_Handle *namestore_handle;
169
170 /**
171 * Iterator for NAMESTORE
172 */
173 struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
174
175 /**
176 * Attribute claim list
177 */
178 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list;
179
180 /**
181 * IDENTITY Operation
182 */
183 struct GNUNET_IDENTITY_Operation *op;
184
185 /**
186 * Identity Provider
187 */
188 struct GNUNET_RECLAIM_Handle *idp;
189
190 /**
191 * Idp Operation
192 */
193 struct GNUNET_RECLAIM_Operation *idp_op;
194
195 /**
196 * Attribute iterator
197 */
198 struct GNUNET_RECLAIM_AttributeIterator *attr_it;
199
200 /**
201 * Ticket iterator
202 */
203 struct GNUNET_RECLAIM_TicketIterator *ticket_it;
204
205 /**
206 * A ticket
207 */
208 struct GNUNET_RECLAIM_Ticket ticket;
209
210 /**
211 * Desired timeout for the lookup (default is no timeout).
212 */
213 struct GNUNET_TIME_Relative timeout;
214
215 /**
216 * ID of a task associated with the resolution process.
217 */
218 struct GNUNET_SCHEDULER_Task *timeout_task;
219
220 /**
221 * The plugin result processor
222 */
223 GNUNET_REST_ResultProcessor proc;
224
225 /**
226 * The closure of the result processor
227 */
228 void *proc_cls;
229
230 /**
231 * The url
232 */
233 char *url;
234
235 /**
236 * Error response message
237 */
238 char *emsg;
239
240 /**
241 * Reponse code
242 */
243 int response_code;
244
245 /**
246 * Response object
247 */
248 json_t *resp_object;
249
250};
251
252/**
253 * Cleanup lookup handle
254 * @param handle Handle to clean up
255 */
256static void
257cleanup_handle (struct RequestHandle *handle)
258{
259 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry;
260 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp;
261 struct EgoEntry *ego_entry;
262 struct EgoEntry *ego_tmp;
263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
264 "Cleaning up\n");
265 if (NULL != handle->resp_object)
266 json_decref (handle->resp_object);
267 if (NULL != handle->timeout_task)
268 GNUNET_SCHEDULER_cancel (handle->timeout_task);
269 if (NULL != handle->identity_handle)
270 GNUNET_IDENTITY_disconnect (handle->identity_handle);
271 if (NULL != handle->attr_it)
272 GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
273 if (NULL != handle->ticket_it)
274 GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
275 if (NULL != handle->idp)
276 GNUNET_RECLAIM_disconnect (handle->idp);
277 if (NULL != handle->url)
278 GNUNET_free (handle->url);
279 if (NULL != handle->emsg)
280 GNUNET_free (handle->emsg);
281 if (NULL != handle->namestore_handle)
282 GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
283 if ( NULL != handle->attr_list )
284 {
285 for (claim_entry = handle->attr_list->list_head;
286 NULL != claim_entry;)
287 {
288 claim_tmp = claim_entry;
289 claim_entry = claim_entry->next;
290 GNUNET_free(claim_tmp->claim);
291 GNUNET_free(claim_tmp);
292 }
293 GNUNET_free (handle->attr_list);
294 }
295 for (ego_entry = handle->ego_head;
296 NULL != ego_entry;)
297 {
298 ego_tmp = ego_entry;
299 ego_entry = ego_entry->next;
300 GNUNET_free (ego_tmp->identifier);
301 GNUNET_free (ego_tmp->keystring);
302 GNUNET_free (ego_tmp);
303 }
304 if (NULL != handle->attr_it)
305 {
306 GNUNET_free(handle->attr_it);
307 }
308 GNUNET_free (handle);
309}
310
311static void
312cleanup_handle_delayed (void *cls)
313{
314 cleanup_handle (cls);
315}
316
317
318/**
319 * Task run on error, sends error message. Cleans up everything.
320 *
321 * @param cls the `struct RequestHandle`
322 */
323static void
324do_error (void *cls)
325{
326 struct RequestHandle *handle = cls;
327 struct MHD_Response *resp;
328 char *json_error;
329
330 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }",
331 handle->emsg);
332 if ( 0 == handle->response_code )
333 {
334 handle->response_code = MHD_HTTP_BAD_REQUEST;
335 }
336 resp = GNUNET_REST_create_response (json_error);
337 MHD_add_response_header (resp, "Content-Type", "application/json");
338 handle->proc (handle->proc_cls, resp, handle->response_code);
339 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
340 GNUNET_free (json_error);
341}
342
343
344/**
345 * Task run on timeout, sends error message. Cleans up everything.
346 *
347 * @param cls the `struct RequestHandle`
348 */
349static void
350do_timeout (void *cls)
351{
352 struct RequestHandle *handle = cls;
353
354 handle->timeout_task = NULL;
355 do_error (handle);
356}
357
358
359static void
360collect_error_cb (void *cls)
361{
362 struct RequestHandle *handle = cls;
363
364 do_error (handle);
365}
366
367static void
368finished_cont (void *cls,
369 int32_t success,
370 const char *emsg)
371{
372 struct RequestHandle *handle = cls;
373 struct MHD_Response *resp;
374
375 resp = GNUNET_REST_create_response (emsg);
376 if (GNUNET_OK != success)
377 {
378 GNUNET_SCHEDULER_add_now (&do_error, handle);
379 return;
380 }
381 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
382 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
383}
384
385
386/**
387 * Return attributes for identity
388 *
389 * @param cls the request handle
390 */
391static void
392return_response (void *cls)
393{
394 char* result_str;
395 struct RequestHandle *handle = cls;
396 struct MHD_Response *resp;
397
398 result_str = json_dumps (handle->resp_object, 0);
399 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
400 resp = GNUNET_REST_create_response (result_str);
401 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
402 GNUNET_free (result_str);
403 cleanup_handle (handle);
404}
405
406static void
407collect_finished_cb (void *cls)
408{
409 struct RequestHandle *handle = cls;
410 //Done
411 handle->attr_it = NULL;
412 handle->ticket_it = NULL;
413 GNUNET_SCHEDULER_add_now (&return_response, handle);
414}
415
416
417/**
418 * Collect all attributes for an ego
419 *
420 */
421static void
422ticket_collect (void *cls,
423 const struct GNUNET_RECLAIM_Ticket *ticket)
424{
425 json_t *json_resource;
426 struct RequestHandle *handle = cls;
427 json_t *value;
428 char* tmp;
429
430 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
431 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
432 sizeof (uint64_t));
433 json_resource = json_object ();
434 GNUNET_free (tmp);
435 json_array_append (handle->resp_object,
436 json_resource);
437
438 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
439 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
440 value = json_string (tmp);
441 json_object_set_new (json_resource,
442 "issuer",
443 value);
444 GNUNET_free (tmp);
445 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
446 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
447 value = json_string (tmp);
448 json_object_set_new (json_resource,
449 "audience",
450 value);
451 GNUNET_free (tmp);
452 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
453 sizeof (uint64_t));
454 value = json_string (tmp);
455 json_object_set_new (json_resource,
456 "rnd",
457 value);
458 GNUNET_free (tmp);
459 GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it);
460}
461
462
463
464/**
465 * List tickets for identity request
466 *
467 * @param con_handle the connection handle
468 * @param url the url
469 * @param cls the RequestHandle
470 */
471static void
472list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
473 const char* url,
474 void *cls)
475{
476 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
477 struct RequestHandle *handle = cls;
478 struct EgoEntry *ego_entry;
479 char *identity;
480
481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
482 handle->url);
483 if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
484 strlen (handle->url))
485 {
486 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
487 GNUNET_SCHEDULER_add_now (&do_error, handle);
488 return;
489 }
490 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
491
492 for (ego_entry = handle->ego_head;
493 NULL != ego_entry;
494 ego_entry = ego_entry->next)
495 if (0 == strcmp (identity, ego_entry->identifier))
496 break;
497 handle->resp_object = json_array ();
498
499 if (NULL == ego_entry)
500 {
501 //Done
502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
503 identity);
504 GNUNET_SCHEDULER_add_now (&return_response, handle);
505 return;
506 }
507 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
508 handle->idp = GNUNET_RECLAIM_connect (cfg);
509 handle->ticket_it = GNUNET_RECLAIM_ticket_iteration_start (handle->idp,
510 priv_key,
511 &collect_error_cb,
512 handle,
513 &ticket_collect,
514 handle,
515 &collect_finished_cb,
516 handle);
517}
518
519
520static void
521add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
522 const char* url,
523 void *cls)
524{
525 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
526 const char* identity;
527 struct RequestHandle *handle = cls;
528 struct EgoEntry *ego_entry;
529 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute;
530 struct GNUNET_TIME_Relative exp;
531 char term_data[handle->rest_handle->data_size+1];
532 json_t *data_json;
533 json_error_t err;
534 struct GNUNET_JSON_Specification attrspec[] = {
535 GNUNET_RECLAIM_JSON_spec_claim (&attribute),
536 GNUNET_JSON_spec_end()
537 };
538
539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
540 handle->url);
541 if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >=
542 strlen (handle->url))
543 {
544 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
545 GNUNET_SCHEDULER_add_now (&do_error, handle);
546 return;
547 }
548 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
549
550 for (ego_entry = handle->ego_head;
551 NULL != ego_entry;
552 ego_entry = ego_entry->next)
553 if (0 == strcmp (identity, ego_entry->identifier))
554 break;
555
556 if (NULL == ego_entry)
557 {
558 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
559 "Identity unknown (%s)\n", identity);
560 return;
561 }
562 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
563
564 if (0 >= handle->rest_handle->data_size)
565 {
566 GNUNET_SCHEDULER_add_now (&do_error, handle);
567 return;
568 }
569
570 term_data[handle->rest_handle->data_size] = '\0';
571 GNUNET_memcpy (term_data,
572 handle->rest_handle->data,
573 handle->rest_handle->data_size);
574 data_json = json_loads (term_data,
575 JSON_DECODE_ANY,
576 &err);
577 GNUNET_assert (GNUNET_OK ==
578 GNUNET_JSON_parse (data_json, attrspec,
579 NULL, NULL));
580 json_decref (data_json);
581 if (NULL == attribute)
582 {
583 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
584 "Unable to parse attribute from %s\n",
585 term_data);
586 GNUNET_SCHEDULER_add_now (&do_error, handle);
587 return;
588 }
589 handle->idp = GNUNET_RECLAIM_connect (cfg);
590 exp = GNUNET_TIME_UNIT_HOURS;
591 handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
592 identity_priv,
593 attribute,
594 &exp,
595 &finished_cont,
596 handle);
597 GNUNET_JSON_parse_free (attrspec);
598}
599
600
601
602/**
603 * Collect all attributes for an ego
604 *
605 */
606static void
607attr_collect (void *cls,
608 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
609 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
610{
611 struct RequestHandle *handle = cls;
612 json_t *attr_obj;
613 const char* type;
614 char* tmp_value;
615
616 if ((NULL == attr->name) || (NULL == attr->data))
617 {
618 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
619 return;
620 }
621
622 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
623 attr->name);
624
625 tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
626 attr->data,
627 attr->data_size);
628
629 attr_obj = json_object ();
630 json_object_set_new (attr_obj,
631 "value",
632 json_string (tmp_value));
633 json_object_set_new (attr_obj,
634 "name",
635 json_string (attr->name));
636 type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
637 json_object_set_new (attr_obj,
638 "type",
639 json_string (type));
640 json_array_append (handle->resp_object,
641 attr_obj);
642 json_decref (attr_obj);
643 GNUNET_free(tmp_value);
644 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
645}
646
647
648
649/**
650 * List attributes for identity request
651 *
652 * @param con_handle the connection handle
653 * @param url the url
654 * @param cls the RequestHandle
655 */
656static void
657list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
658 const char* url,
659 void *cls)
660{
661 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
662 struct RequestHandle *handle = cls;
663 struct EgoEntry *ego_entry;
664 char *identity;
665
666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
667 handle->url);
668 if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >=
669 strlen (handle->url))
670 {
671 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
672 GNUNET_SCHEDULER_add_now (&do_error, handle);
673 return;
674 }
675 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
676
677 for (ego_entry = handle->ego_head;
678 NULL != ego_entry;
679 ego_entry = ego_entry->next)
680 if (0 == strcmp (identity, ego_entry->identifier))
681 break;
682 handle->resp_object = json_array ();
683
684
685 if (NULL == ego_entry)
686 {
687 //Done
688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
689 identity);
690 GNUNET_SCHEDULER_add_now (&return_response, handle);
691 return;
692 }
693 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
694 handle->idp = GNUNET_RECLAIM_connect (cfg);
695 handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
696 priv_key,
697 &collect_error_cb,
698 handle,
699 &attr_collect,
700 handle,
701 &collect_finished_cb,
702 handle);
703}
704
705
706static void
707revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
708 const char* url,
709 void *cls)
710{
711 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
712 struct RequestHandle *handle = cls;
713 struct EgoEntry *ego_entry;
714 struct GNUNET_RECLAIM_Ticket *ticket;
715 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
716 char term_data[handle->rest_handle->data_size+1];
717 json_t *data_json;
718 json_error_t err;
719 struct GNUNET_JSON_Specification tktspec[] = {
720 GNUNET_RECLAIM_JSON_spec_ticket (&ticket),
721 GNUNET_JSON_spec_end()
722 };
723
724 if (0 >= handle->rest_handle->data_size)
725 {
726 GNUNET_SCHEDULER_add_now (&do_error, handle);
727 return;
728 }
729
730 term_data[handle->rest_handle->data_size] = '\0';
731 GNUNET_memcpy (term_data,
732 handle->rest_handle->data,
733 handle->rest_handle->data_size);
734 data_json = json_loads (term_data,
735 JSON_DECODE_ANY,
736 &err);
737 GNUNET_assert (GNUNET_OK ==
738 GNUNET_JSON_parse (data_json, tktspec,
739 NULL, NULL));
740 json_decref (data_json);
741 if (NULL == ticket)
742 {
743 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
744 "Unable to parse ticket from %s\n",
745 term_data);
746 GNUNET_SCHEDULER_add_now (&do_error, handle);
747 return;
748 }
749 if (GNUNET_OK != GNUNET_JSON_parse (data_json,
750 tktspec,
751 NULL, NULL))
752 {
753 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
754 GNUNET_SCHEDULER_add_now (&do_error, handle);
755 GNUNET_JSON_parse_free (tktspec);
756 json_decref (data_json);
757 return;
758 }
759
760 for (ego_entry = handle->ego_head;
761 NULL != ego_entry;
762 ego_entry = ego_entry->next)
763 {
764 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
765 &tmp_pk);
766 if (0 == memcmp (&ticket->identity,
767 &tmp_pk,
768 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
769 break;
770 }
771 if (NULL == ego_entry)
772 {
773 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
774 "Identity unknown\n");
775 GNUNET_JSON_parse_free (tktspec);
776 return;
777 }
778 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
779
780 handle->idp = GNUNET_RECLAIM_connect (cfg);
781 handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
782 identity_priv,
783 ticket,
784 &finished_cont,
785 handle);
786 GNUNET_JSON_parse_free (tktspec);
787}
788
789static void
790consume_cont (void *cls,
791 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
792 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
793{
794 struct RequestHandle *handle = cls;
795 char *val_str;
796 json_t *value;
797
798 if (NULL == identity)
799 {
800 GNUNET_SCHEDULER_add_now (&return_response, handle);
801 return;
802 }
803
804 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
805 attr->name);
806 val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
807 attr->data,
808 attr->data_size);
809 if (NULL == val_str)
810 {
811 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to parse value for: %s\n",
812 attr->name);
813 return;
814 }
815 value = json_string(val_str);
816 json_object_set_new (handle->resp_object,
817 attr->name,
818 value);
819 json_decref (value);
820 GNUNET_free (val_str);
821}
822
823static void
824consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
825 const char* url,
826 void *cls)
827{
828 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
829 struct RequestHandle *handle = cls;
830 struct EgoEntry *ego_entry;
831 struct GNUNET_RECLAIM_Ticket *ticket;
832 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
833 char term_data[handle->rest_handle->data_size+1];
834 json_t *data_json;
835 json_error_t err;
836 struct GNUNET_JSON_Specification tktspec[] = {
837 GNUNET_RECLAIM_JSON_spec_ticket (&ticket),
838 GNUNET_JSON_spec_end ()
839 };
840
841 if (0 >= handle->rest_handle->data_size)
842 {
843 GNUNET_SCHEDULER_add_now (&do_error, handle);
844 return;
845 }
846
847 term_data[handle->rest_handle->data_size] = '\0';
848 GNUNET_memcpy (term_data,
849 handle->rest_handle->data,
850 handle->rest_handle->data_size);
851 data_json = json_loads (term_data,
852 JSON_DECODE_ANY,
853 &err);
854 if (NULL == data_json)
855 {
856 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
857 "Unable to parse JSON Object from %s\n",
858 term_data);
859 GNUNET_SCHEDULER_add_now (&do_error, handle);
860 return;
861 }
862 if (GNUNET_OK != GNUNET_JSON_parse (data_json,
863 tktspec,
864 NULL, NULL))
865 {
866 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
867 GNUNET_SCHEDULER_add_now (&do_error, handle);
868 GNUNET_JSON_parse_free(tktspec);
869 json_decref (data_json);
870 return;
871 }
872 for (ego_entry = handle->ego_head;
873 NULL != ego_entry;
874 ego_entry = ego_entry->next)
875 {
876 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
877 &tmp_pk);
878 if (0 == memcmp (&ticket->audience,
879 &tmp_pk,
880 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
881 break;
882 }
883 if (NULL == ego_entry)
884 {
885 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
886 "Identity unknown\n");
887 GNUNET_JSON_parse_free (tktspec);
888 return;
889 }
890 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
891 handle->resp_object = json_object ();
892 handle->idp = GNUNET_RECLAIM_connect (cfg);
893 handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
894 identity_priv,
895 ticket,
896 &consume_cont,
897 handle);
898 GNUNET_JSON_parse_free (tktspec);
899}
900
901
902
903/**
904 * Respond to OPTIONS request
905 *
906 * @param con_handle the connection handle
907 * @param url the url
908 * @param cls the RequestHandle
909 */
910static void
911options_cont (struct GNUNET_REST_RequestHandle *con_handle,
912 const char* url,
913 void *cls)
914{
915 struct MHD_Response *resp;
916 struct RequestHandle *handle = cls;
917
918 //For now, independent of path return all options
919 resp = GNUNET_REST_create_response (NULL);
920 MHD_add_response_header (resp,
921 "Access-Control-Allow-Methods",
922 allow_methods);
923 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
924 cleanup_handle (handle);
925 return;
926}
927
928/**
929 * Handle rest request
930 *
931 * @param handle the request handle
932 */
933static void
934init_cont (struct RequestHandle *handle)
935{
936 struct GNUNET_REST_RequestHandlerError err;
937 static const struct GNUNET_REST_RequestHandler handlers[] = {
938 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &list_attribute_cont},
939 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &add_attribute_cont},
940 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
941 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
942 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
943 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM,
944 &options_cont},
945 GNUNET_REST_HANDLER_END
946 };
947
948 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
949 handlers,
950 &err,
951 handle))
952 {
953 handle->response_code = err.error_code;
954 GNUNET_SCHEDULER_add_now (&do_error, handle);
955 }
956}
957
958/**
959 * If listing is enabled, prints information about the egos.
960 *
961 * This function is initially called for all egos and then again
962 * whenever a ego's identifier changes or if it is deleted. At the
963 * end of the initial pass over all egos, the function is once called
964 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
965 * be invoked in the future or that there was an error.
966 *
967 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
968 * this function is only called ONCE, and 'NULL' being passed in
969 * 'ego' does indicate an error (i.e. name is taken or no default
970 * value is known). If 'ego' is non-NULL and if '*ctx'
971 * is set in those callbacks, the value WILL be passed to a subsequent
972 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
973 * that one was not NULL).
974 *
975 * When an identity is renamed, this function is called with the
976 * (known) ego but the NEW identifier.
977 *
978 * When an identity is deleted, this function is called with the
979 * (known) ego and "NULL" for the 'identifier'. In this case,
980 * the 'ego' is henceforth invalid (and the 'ctx' should also be
981 * cleaned up).
982 *
983 * @param cls closure
984 * @param ego ego handle
985 * @param ctx context for application to store data for this ego
986 * (during the lifetime of this process, initially NULL)
987 * @param identifier identifier assigned by the user for this ego,
988 * NULL if the user just deleted the ego and it
989 * must thus no longer be used
990 */
991static void
992list_ego (void *cls,
993 struct GNUNET_IDENTITY_Ego *ego,
994 void **ctx,
995 const char *identifier)
996{
997 struct RequestHandle *handle = cls;
998 struct EgoEntry *ego_entry;
999 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1000
1001 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1002 {
1003 handle->state = ID_REST_STATE_POST_INIT;
1004 init_cont (handle);
1005 return;
1006 }
1007 if (ID_REST_STATE_INIT == handle->state) {
1008 ego_entry = GNUNET_new (struct EgoEntry);
1009 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1010 ego_entry->keystring =
1011 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1012 ego_entry->ego = ego;
1013 ego_entry->identifier = GNUNET_strdup (identifier);
1014 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1015 }
1016
1017}
1018
1019static void
1020rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1021 GNUNET_REST_ResultProcessor proc,
1022 void *proc_cls)
1023{
1024 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1025 handle->response_code = 0;
1026 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1027 handle->proc_cls = proc_cls;
1028 handle->proc = proc;
1029 handle->state = ID_REST_STATE_INIT;
1030 handle->rest_handle = rest_handle;
1031
1032 handle->url = GNUNET_strdup (rest_handle->url);
1033 if (handle->url[strlen (handle->url)-1] == '/')
1034 handle->url[strlen (handle->url)-1] = '\0';
1035 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1036 "Connecting...\n");
1037 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1038 &list_ego,
1039 handle);
1040 handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
1041 handle->timeout_task =
1042 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1043 &do_timeout,
1044 handle);
1045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1046 "Connected\n");
1047}
1048
1049/**
1050 * Entry point for the plugin.
1051 *
1052 * @param cls Config info
1053 * @return NULL on error, otherwise the plugin context
1054 */
1055void *
1056libgnunet_plugin_rest_reclaim_init (void *cls)
1057{
1058 static struct Plugin plugin;
1059 struct GNUNET_REST_Plugin *api;
1060
1061 cfg = cls;
1062 if (NULL != plugin.cfg)
1063 return NULL; /* can only initialize once! */
1064 memset (&plugin, 0, sizeof (struct Plugin));
1065 plugin.cfg = cfg;
1066 api = GNUNET_new (struct GNUNET_REST_Plugin);
1067 api->cls = &plugin;
1068 api->name = GNUNET_REST_API_NS_RECLAIM;
1069 api->process_request = &rest_identity_process_request;
1070 GNUNET_asprintf (&allow_methods,
1071 "%s, %s, %s, %s, %s",
1072 MHD_HTTP_METHOD_GET,
1073 MHD_HTTP_METHOD_POST,
1074 MHD_HTTP_METHOD_PUT,
1075 MHD_HTTP_METHOD_DELETE,
1076 MHD_HTTP_METHOD_OPTIONS);
1077
1078 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1079 _("Identity Provider REST API initialized\n"));
1080 return api;
1081}
1082
1083
1084/**
1085 * Exit point from the plugin.
1086 *
1087 * @param cls the plugin context (as returned by "init")
1088 * @return always NULL
1089 */
1090void *
1091libgnunet_plugin_rest_reclaim_done (void *cls)
1092{
1093 struct GNUNET_REST_Plugin *api = cls;
1094 struct Plugin *plugin = api->cls;
1095 plugin->cfg = NULL;
1096
1097 GNUNET_free_non_null (allow_methods);
1098 GNUNET_free (api);
1099 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1100 "Identity Provider REST plugin is finished\n");
1101 return NULL;
1102}
1103
1104/* end of plugin_rest_reclaim.c */