aboutsummaryrefslogtreecommitdiff
path: root/src/rest-plugins/plugin_rest_reclaim.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rest-plugins/plugin_rest_reclaim.c')
-rw-r--r--src/rest-plugins/plugin_rest_reclaim.c1097
1 files changed, 1097 insertions, 0 deletions
diff --git a/src/rest-plugins/plugin_rest_reclaim.c b/src/rest-plugins/plugin_rest_reclaim.c
new file mode 100644
index 000000000..9115a9449
--- /dev/null
+++ b/src/rest-plugins/plugin_rest_reclaim.c
@@ -0,0 +1,1097 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18/**
19 * @author Martin Schanzenbach
20 * @author Philippe Buschmann
21 * @file reclaim/plugin_rest_reclaim.c
22 * @brief GNUnet reclaim REST plugin
23 *
24 */
25
26#include "platform.h"
27#include "gnunet_rest_plugin.h"
28#include "gnunet_identity_service.h"
29#include "gnunet_gns_service.h"
30#include "gnunet_gnsrecord_lib.h"
31#include "gnunet_namestore_service.h"
32#include "gnunet_rest_lib.h"
33#include "gnunet_jsonapi_lib.h"
34#include "gnunet_jsonapi_util.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 json_decref (value);
446 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
447 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
448 value = json_string (tmp);
449 json_object_set_new (json_resource,
450 "audience",
451 value);
452 GNUNET_free (tmp);
453 json_decref (value);
454 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
455 sizeof (uint64_t));
456 value = json_string (tmp);
457 json_object_set_new (json_resource,
458 "rnd",
459 value);
460 GNUNET_free (tmp);
461 json_decref (value);
462 GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it);
463}
464
465
466
467/**
468 * List tickets for identity request
469 *
470 * @param con_handle the connection handle
471 * @param url the url
472 * @param cls the RequestHandle
473 */
474static void
475list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
476 const char* url,
477 void *cls)
478{
479 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
480 struct RequestHandle *handle = cls;
481 struct EgoEntry *ego_entry;
482 char *identity;
483
484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
485 handle->url);
486 if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
487 strlen (handle->url))
488 {
489 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
490 GNUNET_SCHEDULER_add_now (&do_error, handle);
491 return;
492 }
493 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
494
495 for (ego_entry = handle->ego_head;
496 NULL != ego_entry;
497 ego_entry = ego_entry->next)
498 if (0 == strcmp (identity, ego_entry->identifier))
499 break;
500 handle->resp_object = json_array ();
501
502 if (NULL == ego_entry)
503 {
504 //Done
505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
506 identity);
507 GNUNET_SCHEDULER_add_now (&return_response, handle);
508 return;
509 }
510 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
511 handle->idp = GNUNET_RECLAIM_connect (cfg);
512 handle->ticket_it = GNUNET_RECLAIM_ticket_iteration_start (handle->idp,
513 priv_key,
514 &collect_error_cb,
515 handle,
516 &ticket_collect,
517 handle,
518 &collect_finished_cb,
519 handle);
520}
521
522
523static void
524add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
525 const char* url,
526 void *cls)
527{
528 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
529 const char* identity;
530 struct RequestHandle *handle = cls;
531 struct EgoEntry *ego_entry;
532 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute;
533 struct GNUNET_TIME_Relative exp;
534 char term_data[handle->rest_handle->data_size+1];
535 json_t *data_json;
536 json_error_t err;
537 struct GNUNET_JSON_Specification attrspec[] = {
538 GNUNET_RECLAIM_JSON_spec_claim (&attribute),
539 GNUNET_JSON_spec_end()
540 };
541
542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
543 handle->url);
544 if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >=
545 strlen (handle->url))
546 {
547 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
548 GNUNET_SCHEDULER_add_now (&do_error, handle);
549 return;
550 }
551 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
552
553 for (ego_entry = handle->ego_head;
554 NULL != ego_entry;
555 ego_entry = ego_entry->next)
556 if (0 == strcmp (identity, ego_entry->identifier))
557 break;
558
559 if (NULL == ego_entry)
560 {
561 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
562 "Identity unknown (%s)\n", identity);
563 return;
564 }
565 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
566
567 if (0 >= handle->rest_handle->data_size)
568 {
569 GNUNET_SCHEDULER_add_now (&do_error, handle);
570 return;
571 }
572
573 term_data[handle->rest_handle->data_size] = '\0';
574 GNUNET_memcpy (term_data,
575 handle->rest_handle->data,
576 handle->rest_handle->data_size);
577 data_json = json_loads (term_data,
578 JSON_DECODE_ANY,
579 &err);
580 GNUNET_assert (GNUNET_OK ==
581 GNUNET_JSON_parse (data_json, attrspec,
582 NULL, NULL));
583 json_decref (data_json);
584 if (NULL == attribute)
585 {
586 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
587 "Unable to parse attribute from %s\n",
588 term_data);
589 GNUNET_SCHEDULER_add_now (&do_error, handle);
590 return;
591 }
592 handle->idp = GNUNET_RECLAIM_connect (cfg);
593 handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
594 identity_priv,
595 attribute,
596 &exp,
597 &finished_cont,
598 handle);
599 GNUNET_JSON_parse_free (attrspec);
600}
601
602
603
604/**
605 * Collect all attributes for an ego
606 *
607 */
608static void
609attr_collect (void *cls,
610 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
611 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
612{
613 struct RequestHandle *handle = cls;
614 json_t *value;
615 char* tmp_value;
616
617 if ((NULL == attr->name) || (NULL == attr->data))
618 {
619 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
620 return;
621 }
622
623 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
624 attr->name);
625
626 tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
627 attr->data,
628 attr->data_size);
629
630 value = json_string (tmp_value);
631
632 json_object_set_new (handle->resp_object,
633 attr->name,
634 value);
635 json_decref (value);
636 GNUNET_free(tmp_value);
637 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
638}
639
640
641
642/**
643 * List attributes for identity request
644 *
645 * @param con_handle the connection handle
646 * @param url the url
647 * @param cls the RequestHandle
648 */
649static void
650list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
651 const char* url,
652 void *cls)
653{
654 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
655 struct RequestHandle *handle = cls;
656 struct EgoEntry *ego_entry;
657 char *identity;
658
659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
660 handle->url);
661 if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >=
662 strlen (handle->url))
663 {
664 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
665 GNUNET_SCHEDULER_add_now (&do_error, handle);
666 return;
667 }
668 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
669
670 for (ego_entry = handle->ego_head;
671 NULL != ego_entry;
672 ego_entry = ego_entry->next)
673 if (0 == strcmp (identity, ego_entry->identifier))
674 break;
675 handle->resp_object = json_object ();
676
677
678 if (NULL == ego_entry)
679 {
680 //Done
681 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
682 identity);
683 GNUNET_SCHEDULER_add_now (&return_response, handle);
684 return;
685 }
686 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
687 handle->idp = GNUNET_RECLAIM_connect (cfg);
688 handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
689 priv_key,
690 &collect_error_cb,
691 handle,
692 &attr_collect,
693 handle,
694 &collect_finished_cb,
695 handle);
696}
697
698
699static void
700revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
701 const char* url,
702 void *cls)
703{
704 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
705 struct RequestHandle *handle = cls;
706 struct EgoEntry *ego_entry;
707 struct GNUNET_RECLAIM_Ticket *ticket;
708 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
709 char term_data[handle->rest_handle->data_size+1];
710 json_t *data_json;
711 json_error_t err;
712 struct GNUNET_JSON_Specification tktspec[] = {
713 GNUNET_RECLAIM_JSON_spec_ticket (&ticket),
714 GNUNET_JSON_spec_end()
715 };
716
717 if (0 >= handle->rest_handle->data_size)
718 {
719 GNUNET_SCHEDULER_add_now (&do_error, handle);
720 return;
721 }
722
723 term_data[handle->rest_handle->data_size] = '\0';
724 GNUNET_memcpy (term_data,
725 handle->rest_handle->data,
726 handle->rest_handle->data_size);
727 data_json = json_loads (term_data,
728 JSON_DECODE_ANY,
729 &err);
730 GNUNET_assert (GNUNET_OK ==
731 GNUNET_JSON_parse (data_json, tktspec,
732 NULL, NULL));
733 json_decref (data_json);
734 if (NULL == ticket)
735 {
736 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
737 "Unable to parse ticket from %s\n",
738 term_data);
739 GNUNET_SCHEDULER_add_now (&do_error, handle);
740 return;
741 }
742 if (GNUNET_OK != GNUNET_JSON_parse (data_json,
743 tktspec,
744 NULL, NULL))
745 {
746 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
747 GNUNET_SCHEDULER_add_now (&do_error, handle);
748 GNUNET_JSON_parse_free (tktspec);
749 json_decref (data_json);
750 return;
751 }
752
753 for (ego_entry = handle->ego_head;
754 NULL != ego_entry;
755 ego_entry = ego_entry->next)
756 {
757 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
758 &tmp_pk);
759 if (0 == memcmp (&ticket->identity,
760 &tmp_pk,
761 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
762 break;
763 }
764 if (NULL == ego_entry)
765 {
766 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
767 "Identity unknown\n");
768 GNUNET_JSON_parse_free (tktspec);
769 return;
770 }
771 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
772
773 handle->idp = GNUNET_RECLAIM_connect (cfg);
774 handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
775 identity_priv,
776 ticket,
777 &finished_cont,
778 handle);
779 GNUNET_JSON_parse_free (tktspec);
780}
781
782static void
783consume_cont (void *cls,
784 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
785 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
786{
787 struct RequestHandle *handle = cls;
788 char *val_str;
789 json_t *value;
790
791 if (NULL == identity)
792 {
793 GNUNET_SCHEDULER_add_now (&return_response, handle);
794 return;
795 }
796
797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
798 attr->name);
799 val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
800 attr->data,
801 attr->data_size);
802 if (NULL == val_str)
803 {
804 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to parse value for: %s\n",
805 attr->name);
806 return;
807 }
808 value = json_string(val_str);
809 json_object_set_new (handle->resp_object,
810 attr->name,
811 value);
812 json_decref (value);
813 GNUNET_free (val_str);
814}
815
816static void
817consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
818 const char* url,
819 void *cls)
820{
821 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
822 struct RequestHandle *handle = cls;
823 struct EgoEntry *ego_entry;
824 struct GNUNET_RECLAIM_Ticket *ticket;
825 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
826 char term_data[handle->rest_handle->data_size+1];
827 json_t *data_json;
828 json_error_t err;
829 struct GNUNET_JSON_Specification tktspec[] = {
830 GNUNET_RECLAIM_JSON_spec_ticket (&ticket),
831 GNUNET_JSON_spec_end ()
832 };
833
834 if (0 >= handle->rest_handle->data_size)
835 {
836 GNUNET_SCHEDULER_add_now (&do_error, handle);
837 return;
838 }
839
840 term_data[handle->rest_handle->data_size] = '\0';
841 GNUNET_memcpy (term_data,
842 handle->rest_handle->data,
843 handle->rest_handle->data_size);
844 data_json = json_loads (term_data,
845 JSON_DECODE_ANY,
846 &err);
847 if (NULL == data_json)
848 {
849 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
850 "Unable to parse JSON Object from %s\n",
851 term_data);
852 GNUNET_SCHEDULER_add_now (&do_error, handle);
853 return;
854 }
855 if (GNUNET_OK != GNUNET_JSON_parse (data_json,
856 tktspec,
857 NULL, NULL))
858 {
859 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
860 GNUNET_SCHEDULER_add_now (&do_error, handle);
861 GNUNET_JSON_parse_free(tktspec);
862 json_decref (data_json);
863 return;
864 }
865 for (ego_entry = handle->ego_head;
866 NULL != ego_entry;
867 ego_entry = ego_entry->next)
868 {
869 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
870 &tmp_pk);
871 if (0 == memcmp (&ticket->audience,
872 &tmp_pk,
873 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
874 break;
875 }
876 if (NULL == ego_entry)
877 {
878 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
879 "Identity unknown\n");
880 GNUNET_JSON_parse_free (tktspec);
881 return;
882 }
883 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
884 handle->resp_object = json_object ();
885 handle->idp = GNUNET_RECLAIM_connect (cfg);
886 handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
887 identity_priv,
888 ticket,
889 &consume_cont,
890 handle);
891 GNUNET_JSON_parse_free (tktspec);
892}
893
894
895
896/**
897 * Respond to OPTIONS request
898 *
899 * @param con_handle the connection handle
900 * @param url the url
901 * @param cls the RequestHandle
902 */
903static void
904options_cont (struct GNUNET_REST_RequestHandle *con_handle,
905 const char* url,
906 void *cls)
907{
908 struct MHD_Response *resp;
909 struct RequestHandle *handle = cls;
910
911 //For now, independent of path return all options
912 resp = GNUNET_REST_create_response (NULL);
913 MHD_add_response_header (resp,
914 "Access-Control-Allow-Methods",
915 allow_methods);
916 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
917 cleanup_handle (handle);
918 return;
919}
920
921/**
922 * Handle rest request
923 *
924 * @param handle the request handle
925 */
926static void
927init_cont (struct RequestHandle *handle)
928{
929 struct GNUNET_REST_RequestHandlerError err;
930 static const struct GNUNET_REST_RequestHandler handlers[] = {
931 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &list_attribute_cont},
932 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &add_attribute_cont},
933 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
934 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
935 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
936 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM,
937 &options_cont},
938 GNUNET_REST_HANDLER_END
939 };
940
941 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
942 handlers,
943 &err,
944 handle))
945 {
946 handle->response_code = err.error_code;
947 GNUNET_SCHEDULER_add_now (&do_error, handle);
948 }
949}
950
951/**
952 * If listing is enabled, prints information about the egos.
953 *
954 * This function is initially called for all egos and then again
955 * whenever a ego's identifier changes or if it is deleted. At the
956 * end of the initial pass over all egos, the function is once called
957 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
958 * be invoked in the future or that there was an error.
959 *
960 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
961 * this function is only called ONCE, and 'NULL' being passed in
962 * 'ego' does indicate an error (i.e. name is taken or no default
963 * value is known). If 'ego' is non-NULL and if '*ctx'
964 * is set in those callbacks, the value WILL be passed to a subsequent
965 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
966 * that one was not NULL).
967 *
968 * When an identity is renamed, this function is called with the
969 * (known) ego but the NEW identifier.
970 *
971 * When an identity is deleted, this function is called with the
972 * (known) ego and "NULL" for the 'identifier'. In this case,
973 * the 'ego' is henceforth invalid (and the 'ctx' should also be
974 * cleaned up).
975 *
976 * @param cls closure
977 * @param ego ego handle
978 * @param ctx context for application to store data for this ego
979 * (during the lifetime of this process, initially NULL)
980 * @param identifier identifier assigned by the user for this ego,
981 * NULL if the user just deleted the ego and it
982 * must thus no longer be used
983 */
984static void
985list_ego (void *cls,
986 struct GNUNET_IDENTITY_Ego *ego,
987 void **ctx,
988 const char *identifier)
989{
990 struct RequestHandle *handle = cls;
991 struct EgoEntry *ego_entry;
992 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
993
994 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
995 {
996 handle->state = ID_REST_STATE_POST_INIT;
997 init_cont (handle);
998 return;
999 }
1000 if (ID_REST_STATE_INIT == handle->state) {
1001 ego_entry = GNUNET_new (struct EgoEntry);
1002 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1003 ego_entry->keystring =
1004 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1005 ego_entry->ego = ego;
1006 ego_entry->identifier = GNUNET_strdup (identifier);
1007 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1008 }
1009
1010}
1011
1012static void
1013rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1014 GNUNET_REST_ResultProcessor proc,
1015 void *proc_cls)
1016{
1017 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1018 handle->response_code = 0;
1019 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1020 handle->proc_cls = proc_cls;
1021 handle->proc = proc;
1022 handle->state = ID_REST_STATE_INIT;
1023 handle->rest_handle = rest_handle;
1024
1025 handle->url = GNUNET_strdup (rest_handle->url);
1026 if (handle->url[strlen (handle->url)-1] == '/')
1027 handle->url[strlen (handle->url)-1] = '\0';
1028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1029 "Connecting...\n");
1030 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1031 &list_ego,
1032 handle);
1033 handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
1034 handle->timeout_task =
1035 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1036 &do_timeout,
1037 handle);
1038 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1039 "Connected\n");
1040}
1041
1042/**
1043 * Entry point for the plugin.
1044 *
1045 * @param cls Config info
1046 * @return NULL on error, otherwise the plugin context
1047 */
1048void *
1049libgnunet_plugin_rest_reclaim_init (void *cls)
1050{
1051 static struct Plugin plugin;
1052 struct GNUNET_REST_Plugin *api;
1053
1054 cfg = cls;
1055 if (NULL != plugin.cfg)
1056 return NULL; /* can only initialize once! */
1057 memset (&plugin, 0, sizeof (struct Plugin));
1058 plugin.cfg = cfg;
1059 api = GNUNET_new (struct GNUNET_REST_Plugin);
1060 api->cls = &plugin;
1061 api->name = GNUNET_REST_API_NS_RECLAIM;
1062 api->process_request = &rest_identity_process_request;
1063 GNUNET_asprintf (&allow_methods,
1064 "%s, %s, %s, %s, %s",
1065 MHD_HTTP_METHOD_GET,
1066 MHD_HTTP_METHOD_POST,
1067 MHD_HTTP_METHOD_PUT,
1068 MHD_HTTP_METHOD_DELETE,
1069 MHD_HTTP_METHOD_OPTIONS);
1070
1071 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1072 _("Identity Provider REST API initialized\n"));
1073 return api;
1074}
1075
1076
1077/**
1078 * Exit point from the plugin.
1079 *
1080 * @param cls the plugin context (as returned by "init")
1081 * @return always NULL
1082 */
1083void *
1084libgnunet_plugin_rest_reclaim_done (void *cls)
1085{
1086 struct GNUNET_REST_Plugin *api = cls;
1087 struct Plugin *plugin = api->cls;
1088 plugin->cfg = NULL;
1089
1090 GNUNET_free_non_null (allow_methods);
1091 GNUNET_free (api);
1092 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1093 "Identity Provider REST plugin is finished\n");
1094 return NULL;
1095}
1096
1097/* end of plugin_rest_reclaim.c */