diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gns/plugin_rest_gns.c | 681 | ||||
-rw-r--r-- | src/gns/plugin_rest_gns2.c | 717 | ||||
-rw-r--r-- | src/identity/plugin_rest_identity.c | 910 | ||||
-rwxr-xr-x | src/identity/test_plugin_identity_rest.sh | 252 | ||||
-rwxr-xr-x | src/identity/test_plugin_rest_identity.sh | 216 |
5 files changed, 1849 insertions, 927 deletions
diff --git a/src/gns/plugin_rest_gns.c b/src/gns/plugin_rest_gns.c index 2b729db54..22c908275 100644 --- a/src/gns/plugin_rest_gns.c +++ b/src/gns/plugin_rest_gns.c | |||
@@ -2,51 +2,50 @@ | |||
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2012-2015 GNUnet e.V. | 3 | Copyright (C) 2012-2015 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software: you can redistribute it and/or modify it | 5 | GNUnet is free software; you can redistribute it and/or modify |
6 | under the terms of the GNU Affero General Public License as published | 6 | it under the terms of the GNU General Public License as published |
7 | by the Free Software Foundation, either version 3 of the License, | 7 | by the Free Software Foundation; either version 3, or (at your |
8 | or (at your option) any later version. | 8 | option) any later version. |
9 | 9 | ||
10 | GNUnet is distributed in the hope that it will be useful, but | 10 | GNUnet is distributed in the hope that it will be useful, but |
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Affero General Public License for more details. | 13 | General Public License for more details. |
14 | 14 | ||
15 | You should have received a copy of the GNU Affero General Public License | 15 | You should have received a copy of the GNU General Public License |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 16 | along with GNUnet; see the file COPYING. If not, write to the |
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
17 | */ | 19 | */ |
18 | /** | 20 | /** |
19 | * @author Martin Schanzenbach | 21 | * @author Philippe Buschmann |
20 | * @file gns/plugin_rest_gns.c | 22 | * @file gns/plugin_rest_gns.c |
21 | * @brief GNUnet GNS REST plugin | 23 | * @brief GNUnet Gns REST plugin |
22 | * | ||
23 | */ | 24 | */ |
24 | 25 | ||
25 | #include "platform.h" | 26 | #include "platform.h" |
26 | #include "gnunet_rest_plugin.h" | 27 | #include "gnunet_rest_plugin.h" |
27 | #include <gnunet_dnsparser_lib.h> | 28 | #include "gnunet_rest_lib.h" |
28 | #include <gnunet_identity_service.h> | 29 | #include "gnunet_gnsrecord_lib.h" |
29 | #include <gnunet_gnsrecord_lib.h> | 30 | #include "gnunet_gns_service.h" |
30 | #include <gnunet_namestore_service.h> | 31 | #include "microhttpd.h" |
31 | #include <gnunet_gns_service.h> | ||
32 | #include <gnunet_rest_lib.h> | ||
33 | #include <gnunet_jsonapi_lib.h> | ||
34 | #include <gnunet_jsonapi_util.h> | ||
35 | #include <jansson.h> | 32 | #include <jansson.h> |
36 | 33 | ||
37 | #define GNUNET_REST_API_NS_GNS "/gns" | 34 | #define GNUNET_REST_API_NS_GNS "/gns" |
38 | 35 | ||
39 | #define GNUNET_REST_JSONAPI_GNS_RECORD_TYPE "record_type" | 36 | #define GNUNET_REST_PARAMETER_GNS_NAME "name" |
40 | |||
41 | #define GNUNET_REST_JSONAPI_GNS_TYPEINFO "gns_name" | ||
42 | 37 | ||
43 | #define GNUNET_REST_JSONAPI_GNS_RECORD "records" | 38 | #define GNUNET_REST_PARAMETER_GNS_RECORD_TYPE "record_type" |
44 | 39 | ||
45 | #define GNUNET_REST_JSONAPI_GNS_EGO "ego" | 40 | /** |
46 | 41 | * The configuration handle | |
47 | #define GNUNET_REST_JSONAPI_GNS_PKEY "pkey" | 42 | */ |
43 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
48 | 44 | ||
49 | #define GNUNET_REST_JSONAPI_GNS_OPTIONS "options" | 45 | /** |
46 | * HTTP methods allows for this plugin | ||
47 | */ | ||
48 | static char* allow_methods; | ||
50 | 49 | ||
51 | /** | 50 | /** |
52 | * @brief struct returned by the initialization function of the plugin | 51 | * @brief struct returned by the initialization function of the plugin |
@@ -56,54 +55,45 @@ struct Plugin | |||
56 | const struct GNUNET_CONFIGURATION_Handle *cfg; | 55 | const struct GNUNET_CONFIGURATION_Handle *cfg; |
57 | }; | 56 | }; |
58 | 57 | ||
59 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
60 | 58 | ||
61 | struct LookupHandle | 59 | |
60 | struct RequestHandle | ||
62 | { | 61 | { |
63 | /** | ||
64 | * Handle to GNS service. | ||
65 | */ | ||
66 | struct GNUNET_GNS_Handle *gns; | ||
67 | 62 | ||
68 | /** | 63 | /** |
69 | * Desired timeout for the lookup (default is no timeout). | 64 | * Connection to GNS |
70 | */ | 65 | */ |
71 | struct GNUNET_TIME_Relative timeout; | 66 | struct GNUNET_GNS_Handle *gns; |
72 | 67 | ||
73 | /** | 68 | /** |
74 | * Handle to lookup request | 69 | * Active GNS lookup |
75 | */ | 70 | */ |
76 | struct GNUNET_GNS_LookupRequest *lookup_request; | 71 | struct GNUNET_GNS_LookupWithTldRequest *gns_lookup; |
77 | 72 | ||
78 | /** | 73 | /** |
79 | * Handle to rest request | 74 | * Name to look up |
80 | */ | 75 | */ |
81 | struct GNUNET_REST_RequestHandle *rest_handle; | 76 | char *name; |
82 | 77 | ||
83 | /** | 78 | /** |
84 | * Lookup an ego with the identity service. | 79 | * Record type to look up |
85 | */ | 80 | */ |
86 | struct GNUNET_IDENTITY_EgoLookup *el; | 81 | int record_type; |
87 | 82 | ||
88 | /** | 83 | /** |
89 | * Handle for identity service. | 84 | * Rest connection |
90 | */ | 85 | */ |
91 | struct GNUNET_IDENTITY_Handle *identity; | 86 | struct GNUNET_REST_RequestHandle *rest_handle; |
92 | 87 | ||
93 | /** | 88 | /** |
94 | * Active operation on identity service. | 89 | * Desired timeout for the lookup (default is no timeout). |
95 | */ | 90 | */ |
96 | struct GNUNET_IDENTITY_Operation *id_op; | 91 | struct GNUNET_TIME_Relative timeout; |
97 | 92 | ||
98 | /** | 93 | /** |
99 | * ID of a task associated with the resolution process. | 94 | * ID of a task associated with the resolution process. |
100 | */ | 95 | */ |
101 | struct GNUNET_SCHEDULER_Task * timeout_task; | 96 | struct GNUNET_SCHEDULER_Task *timeout_task; |
102 | |||
103 | /** | ||
104 | * The root of the received JSON or NULL | ||
105 | */ | ||
106 | json_t *json_root; | ||
107 | 97 | ||
108 | /** | 98 | /** |
109 | * The plugin result processor | 99 | * The plugin result processor |
@@ -116,49 +106,17 @@ struct LookupHandle | |||
116 | void *proc_cls; | 106 | void *proc_cls; |
117 | 107 | ||
118 | /** | 108 | /** |
119 | * The name to look up | 109 | * The url |
120 | */ | ||
121 | char *name; | ||
122 | |||
123 | /** | ||
124 | * The ego to use | ||
125 | * In string representation from JSON | ||
126 | */ | ||
127 | const char *ego_str; | ||
128 | |||
129 | /** | ||
130 | * The Pkey to use | ||
131 | * In string representation from JSON | ||
132 | */ | ||
133 | const char *pkey_str; | ||
134 | |||
135 | /** | ||
136 | * The record type | ||
137 | */ | ||
138 | int type; | ||
139 | |||
140 | /** | ||
141 | * The public key of to use for lookup | ||
142 | */ | 110 | */ |
143 | struct GNUNET_CRYPTO_EcdsaPublicKey pkey; | 111 | char *url; |
144 | 112 | ||
145 | /** | 113 | /** |
146 | * The public key to use for lookup | 114 | * Error response message |
147 | */ | 115 | */ |
148 | struct GNUNET_CRYPTO_EcdsaPublicKey pkeym; | 116 | char *emsg; |
149 | 117 | ||
150 | /** | 118 | /** |
151 | * The resolver options | 119 | * Reponse code |
152 | */ | ||
153 | enum GNUNET_GNS_LocalOptions options; | ||
154 | |||
155 | /** | ||
156 | * the shorten key | ||
157 | */ | ||
158 | struct GNUNET_CRYPTO_EcdsaPrivateKey shorten_key; | ||
159 | |||
160 | /** | ||
161 | * HTTP response code | ||
162 | */ | 120 | */ |
163 | int response_code; | 121 | int response_code; |
164 | 122 | ||
@@ -166,39 +124,19 @@ struct LookupHandle | |||
166 | 124 | ||
167 | 125 | ||
168 | /** | 126 | /** |
169 | * Cleanup lookup handle. | 127 | * Cleanup lookup handle |
170 | * | ||
171 | * @param handle Handle to clean up | 128 | * @param handle Handle to clean up |
172 | */ | 129 | */ |
173 | static void | 130 | static void |
174 | cleanup_handle (struct LookupHandle *handle) | 131 | cleanup_handle (struct RequestHandle *handle) |
175 | { | 132 | { |
176 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 133 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
177 | "Cleaning up\n"); | 134 | "Cleaning up\n"); |
178 | if (NULL != handle->json_root) | ||
179 | json_decref (handle->json_root); | ||
180 | 135 | ||
181 | if (NULL != handle->name) | 136 | if (NULL != handle->gns_lookup) |
182 | GNUNET_free (handle->name); | ||
183 | if (NULL != handle->el) | ||
184 | { | ||
185 | GNUNET_IDENTITY_ego_lookup_cancel (handle->el); | ||
186 | handle->el = NULL; | ||
187 | } | ||
188 | if (NULL != handle->id_op) | ||
189 | { | 137 | { |
190 | GNUNET_IDENTITY_cancel (handle->id_op); | 138 | GNUNET_GNS_lookup_with_tld_cancel (handle->gns_lookup); |
191 | handle->id_op = NULL; | 139 | handle->gns_lookup = NULL; |
192 | } | ||
193 | if (NULL != handle->lookup_request) | ||
194 | { | ||
195 | GNUNET_GNS_lookup_cancel (handle->lookup_request); | ||
196 | handle->lookup_request = NULL; | ||
197 | } | ||
198 | if (NULL != handle->identity) | ||
199 | { | ||
200 | GNUNET_IDENTITY_disconnect (handle->identity); | ||
201 | handle->identity = NULL; | ||
202 | } | 140 | } |
203 | if (NULL != handle->gns) | 141 | if (NULL != handle->gns) |
204 | { | 142 | { |
@@ -209,378 +147,190 @@ cleanup_handle (struct LookupHandle *handle) | |||
209 | if (NULL != handle->timeout_task) | 147 | if (NULL != handle->timeout_task) |
210 | { | 148 | { |
211 | GNUNET_SCHEDULER_cancel (handle->timeout_task); | 149 | GNUNET_SCHEDULER_cancel (handle->timeout_task); |
150 | handle->timeout_task = NULL; | ||
212 | } | 151 | } |
152 | if (NULL != handle->url) | ||
153 | GNUNET_free (handle->url); | ||
154 | if (NULL != handle->name) | ||
155 | GNUNET_free (handle->name); | ||
156 | if (NULL != handle->emsg) | ||
157 | GNUNET_free (handle->emsg); | ||
158 | |||
213 | GNUNET_free (handle); | 159 | GNUNET_free (handle); |
214 | } | 160 | } |
215 | 161 | ||
216 | 162 | ||
217 | /** | 163 | /** |
218 | * Task run on shutdown. Cleans up everything. | 164 | * Task run on errors. Reports an error and cleans up everything. |
219 | * | 165 | * |
220 | * @param cls unused | 166 | * @param cls the `struct RequestHandle` |
221 | * @param tc scheduler context | ||
222 | */ | 167 | */ |
223 | static void | 168 | static void |
224 | do_error (void *cls) | 169 | do_error (void *cls) |
225 | { | 170 | { |
226 | struct LookupHandle *handle = cls; | 171 | struct RequestHandle *handle = cls; |
227 | struct MHD_Response *resp; | 172 | struct MHD_Response *resp; |
173 | char *json_error; | ||
228 | 174 | ||
229 | resp = GNUNET_REST_create_response (NULL); | 175 | if (NULL == handle->emsg) |
176 | handle->emsg = GNUNET_strdup("Unknown Error"); | ||
177 | |||
178 | GNUNET_asprintf (&json_error, "{\"error\": \"%s\"}", handle->emsg); | ||
179 | |||
180 | if (0 == handle->response_code) | ||
181 | handle->response_code = MHD_HTTP_OK; | ||
182 | |||
183 | resp = GNUNET_REST_create_response (json_error); | ||
230 | handle->proc (handle->proc_cls, resp, handle->response_code); | 184 | handle->proc (handle->proc_cls, resp, handle->response_code); |
231 | cleanup_handle (handle); | 185 | cleanup_handle (handle); |
186 | GNUNET_free(json_error); | ||
232 | } | 187 | } |
233 | 188 | ||
234 | 189 | ||
235 | /** | 190 | /** |
236 | * Create json representation of a GNSRECORD | 191 | * Iterator called on obtained result for a GNS lookup. |
237 | * | 192 | * |
238 | * @param rd the GNSRECORD_Data | 193 | * @param cls closure with the object |
194 | * @param was_gns #GNUNET_NO if name was not a GNS name | ||
195 | * @param rd_count number of records in @a rd | ||
196 | * @param rd the records in reply | ||
239 | */ | 197 | */ |
240 | static json_t * | 198 | static void |
241 | gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd) | 199 | handle_gns_response (void *cls, |
200 | int was_gns, | ||
201 | uint32_t rd_count, | ||
202 | const struct GNUNET_GNSRECORD_Data *rd) | ||
242 | { | 203 | { |
243 | const char *typename; | 204 | struct RequestHandle *handle = cls; |
244 | char *string_val; | 205 | struct MHD_Response *resp; |
245 | const char *exp_str; | 206 | json_t *result_array; |
246 | json_t *record_obj; | 207 | json_t *record_obj; |
208 | char *record_value; | ||
209 | char *result; | ||
247 | 210 | ||
248 | typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type); | 211 | handle->gns_lookup = NULL; |
249 | string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type, | ||
250 | rd->data, | ||
251 | rd->data_size); | ||
252 | 212 | ||
253 | if (NULL == string_val) | 213 | if (GNUNET_NO == was_gns) |
254 | { | 214 | { |
255 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 215 | handle->emsg = GNUNET_strdup("Name not found in GNS"); |
256 | "Record of type %d malformed, skipping\n", | 216 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
257 | (int) rd->record_type); | 217 | return; |
258 | return NULL; | ||
259 | } | ||
260 | record_obj = json_object (); | ||
261 | json_object_set_new (record_obj, "type", json_string (typename)); | ||
262 | json_object_set_new (record_obj, "value", json_string (string_val)); | ||
263 | GNUNET_free (string_val); | ||
264 | |||
265 | if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags) | ||
266 | { | ||
267 | struct GNUNET_TIME_Relative time_rel; | ||
268 | time_rel.rel_value_us = rd->expiration_time; | ||
269 | exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1); | ||
270 | } | 218 | } |
271 | else | 219 | if (0 == rd_count) |
272 | { | 220 | { |
273 | struct GNUNET_TIME_Absolute time_abs; | 221 | handle->emsg = GNUNET_strdup("No result found"); |
274 | time_abs.abs_value_us = rd->expiration_time; | 222 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
275 | exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs); | 223 | return; |
276 | } | 224 | } |
277 | json_object_set_new (record_obj, "expiration_time", json_string (exp_str)); | ||
278 | |||
279 | json_object_set_new (record_obj, "expired", | ||
280 | json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd))); | ||
281 | return record_obj; | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * Function called with the result of a GNS lookup. | ||
286 | * | ||
287 | * @param cls the 'const char *' name that was resolved | ||
288 | * @param rd_count number of records returned | ||
289 | * @param rd array of @a rd_count records with the results | ||
290 | */ | ||
291 | static void | ||
292 | process_lookup_result (void *cls, uint32_t rd_count, | ||
293 | const struct GNUNET_GNSRECORD_Data *rd) | ||
294 | { | ||
295 | struct LookupHandle *handle = cls; | ||
296 | struct MHD_Response *resp; | ||
297 | struct GNUNET_JSONAPI_Document *json_document; | ||
298 | struct GNUNET_JSONAPI_Resource *json_resource; | ||
299 | uint32_t i; | ||
300 | char *result; | ||
301 | json_t *result_array; | ||
302 | json_t *record_obj; | ||
303 | 225 | ||
304 | result_array = json_array(); | 226 | result_array = json_array(); |
305 | json_document = GNUNET_JSONAPI_document_new (); | 227 | for (uint32_t i=0;i<rd_count;i++) |
306 | json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_GNS_TYPEINFO, handle->name); | ||
307 | handle->lookup_request = NULL; | ||
308 | for (i=0; i<rd_count; i++) | ||
309 | { | 228 | { |
310 | if ( (rd[i].record_type != handle->type) && | 229 | if ((rd[i].record_type != handle->record_type) && |
311 | (GNUNET_GNSRECORD_TYPE_ANY != handle->type) ) | 230 | (GNUNET_GNSRECORD_TYPE_ANY != handle->record_type) ) |
231 | { | ||
312 | continue; | 232 | continue; |
313 | record_obj = gnsrecord_to_json (&(rd[i])); | 233 | } |
234 | |||
235 | record_value = GNUNET_GNSRECORD_value_to_string (rd->record_type, | ||
236 | rd->data, | ||
237 | rd->data_size); | ||
238 | record_obj = json_string(record_value); | ||
314 | json_array_append (result_array, record_obj); | 239 | json_array_append (result_array, record_obj); |
315 | json_decref (record_obj); | 240 | json_decref (record_obj); |
316 | } | 241 | } |
317 | GNUNET_JSONAPI_resource_add_attr (json_resource, | 242 | |
318 | GNUNET_REST_JSONAPI_GNS_RECORD, | 243 | result = json_dumps(result_array, 0); |
319 | result_array); | ||
320 | GNUNET_JSONAPI_document_resource_add (json_document, json_resource); | ||
321 | GNUNET_JSONAPI_document_serialize (json_document, &result); | ||
322 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result); | 244 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result); |
323 | json_decref (result_array); | ||
324 | GNUNET_JSONAPI_document_delete (json_document); | ||
325 | resp = GNUNET_REST_create_response (result); | 245 | resp = GNUNET_REST_create_response (result); |
326 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); | 246 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); |
327 | GNUNET_free (result); | 247 | GNUNET_free (result); |
248 | json_decref (result_array); | ||
328 | cleanup_handle (handle); | 249 | cleanup_handle (handle); |
329 | } | 250 | } |
330 | 251 | ||
331 | 252 | ||
332 | /** | 253 | /** |
333 | * Perform the actual resolution, starting with the zone | 254 | * Handle gns GET request |
334 | * identified by the given public key and the shorten zone. | ||
335 | * | 255 | * |
336 | * @param pkey public key to use for the zone, can be NULL | 256 | * @param con_handle the connection handle |
257 | * @param url the url | ||
258 | * @param cls the RequestHandle | ||
337 | */ | 259 | */ |
338 | static void | 260 | void |
339 | lookup_with_public_key (struct LookupHandle *handle) | 261 | get_gns_cont (struct GNUNET_REST_RequestHandle *con_handle, |
262 | const char* url, | ||
263 | void *cls) | ||
340 | { | 264 | { |
341 | if (UINT32_MAX == handle->type) | 265 | struct RequestHandle *handle = cls; |
342 | { | 266 | struct GNUNET_HashCode key; |
343 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 267 | int conversion_state; |
344 | _("Invalid typename specified, assuming `ANY'\n")); | 268 | |
345 | handle->type = GNUNET_GNSRECORD_TYPE_ANY; | 269 | GNUNET_CRYPTO_hash (GNUNET_REST_PARAMETER_GNS_NAME, |
346 | } | 270 | strlen (GNUNET_REST_PARAMETER_GNS_NAME), |
347 | if (NULL != handle->name) | 271 | &key); |
348 | { | 272 | if ( GNUNET_NO |
349 | handle->lookup_request = GNUNET_GNS_lookup (handle->gns, | 273 | == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, |
350 | handle->name, | 274 | &key)) |
351 | &handle->pkey, | ||
352 | handle->type, | ||
353 | handle->options, | ||
354 | &process_lookup_result, | ||
355 | handle); | ||
356 | } | ||
357 | else | ||
358 | { | 275 | { |
276 | handle->emsg = GNUNET_strdup("Parameter name is missing"); | ||
359 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 277 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
360 | return; | 278 | return; |
361 | } | 279 | } |
362 | } | 280 | handle->name = GNUNET_strdup( |
363 | 281 | GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,&key)); | |
364 | 282 | ||
365 | /** | 283 | GNUNET_CRYPTO_hash (GNUNET_REST_PARAMETER_GNS_RECORD_TYPE, |
366 | * Method called to with the ego we are to use for the lookup, | 284 | strlen (GNUNET_REST_PARAMETER_GNS_RECORD_TYPE), |
367 | * when the ego is determined by a name. | 285 | &key); |
368 | * | 286 | if ( GNUNET_NO |
369 | * @param cls closure (NULL, unused) | 287 | == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, |
370 | * @param ego ego handle, NULL if not found | 288 | &key)) |
371 | */ | ||
372 | static void | ||
373 | identity_zone_cb (void *cls, | ||
374 | const struct GNUNET_IDENTITY_Ego *ego) | ||
375 | { | ||
376 | struct LookupHandle *handle = cls; | ||
377 | |||
378 | handle->el = NULL; | ||
379 | if (NULL == ego) | ||
380 | { | 289 | { |
381 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 290 | handle->emsg = GNUNET_strdup("Parameter record_type is missing"); |
382 | _("Ego for not found, cannot perform lookup.\n")); | ||
383 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 291 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
384 | return; | 292 | return; |
385 | } | 293 | } |
386 | else | 294 | conversion_state = sscanf ( |
387 | { | 295 | GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key),"%u", |
388 | GNUNET_IDENTITY_ego_get_public_key (ego, &handle->pkey); | 296 | &(handle->record_type)); |
389 | lookup_with_public_key (handle); | ||
390 | } | ||
391 | json_decref(handle->json_root); | ||
392 | } | ||
393 | |||
394 | |||
395 | /** | ||
396 | * Method called to with the ego we are to use for the lookup, | ||
397 | * when the ego is the one for the default master zone. | ||
398 | * | ||
399 | * @param cls closure (NULL, unused) | ||
400 | * @param ego ego handle, NULL if not found | ||
401 | * @param ctx context for application to store data for this ego | ||
402 | * (during the lifetime of this process, initially NULL) | ||
403 | * @param name name assigned by the user for this ego, | ||
404 | * NULL if the user just deleted the ego and it | ||
405 | * must thus no longer be used | ||
406 | */ | ||
407 | static void | ||
408 | identity_master_cb (void *cls, | ||
409 | struct GNUNET_IDENTITY_Ego *ego, | ||
410 | void **ctx, | ||
411 | const char *name) | ||
412 | { | ||
413 | const char *dot; | ||
414 | struct LookupHandle *handle = cls; | ||
415 | 297 | ||
416 | handle->id_op = NULL; | 298 | if((EOF == conversion_state) || (0 == conversion_state)) |
417 | if (NULL == ego) | ||
418 | { | 299 | { |
419 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 300 | handle->record_type = GNUNET_GNSRECORD_TYPE_ANY; |
420 | _("Ego for `gns-master' not found, cannot perform lookup. Did you run gnunet-gns-import.sh?\n")); | ||
421 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
422 | return; | ||
423 | } | 301 | } |
424 | GNUNET_IDENTITY_ego_get_public_key (ego, | ||
425 | &handle->pkey); | ||
426 | /* main name is our own master zone, do no look for that in the DHT */ | ||
427 | handle->options = GNUNET_GNS_LO_LOCAL_MASTER; | ||
428 | /* if the name is of the form 'label.gnu', never go to the DHT */ | ||
429 | dot = NULL; | ||
430 | if (NULL != handle->name) | ||
431 | dot = strchr (handle->name, '.'); | ||
432 | if ( (NULL != dot) && | ||
433 | (0 == strcasecmp (dot, ".gnu")) ) | ||
434 | handle->options = GNUNET_GNS_LO_NO_DHT; | ||
435 | lookup_with_public_key (handle); | ||
436 | } | ||
437 | 302 | ||
438 | /** | ||
439 | * Parse REST uri for name and record type | ||
440 | * | ||
441 | * @param url Url to parse | ||
442 | * @param handle lookup handle to populate | ||
443 | * @return GNUNET_SYSERR on error | ||
444 | */ | ||
445 | static int | ||
446 | parse_url (const char *url, struct LookupHandle *handle) | ||
447 | { | ||
448 | char *name; | ||
449 | char tmp_url[strlen(url)+1]; | ||
450 | char *tok; | ||
451 | |||
452 | strcpy (tmp_url, url); | ||
453 | tok = strtok ((char*)tmp_url, "/"); | ||
454 | if (NULL == tok) | ||
455 | return GNUNET_SYSERR; | ||
456 | name = strtok (NULL, "/"); | ||
457 | if (NULL == name) | ||
458 | return GNUNET_SYSERR; | ||
459 | GNUNET_asprintf (&handle->name, | ||
460 | "%s", | ||
461 | name); | ||
462 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
463 | "Got name: %s\n", handle->name); | ||
464 | return GNUNET_OK; | ||
465 | } | ||
466 | |||
467 | |||
468 | static void | ||
469 | get_gns_cont (struct GNUNET_REST_RequestHandle *conndata_handle, | ||
470 | const char* url, | ||
471 | void *cls) | ||
472 | { | ||
473 | struct LookupHandle *handle = cls; | ||
474 | struct GNUNET_HashCode key; | ||
475 | |||
476 | //parse name and type from url | ||
477 | if (GNUNET_OK != parse_url (url, handle)) | ||
478 | { | ||
479 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error parsing url...\n"); | ||
480 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
481 | return; | ||
482 | } | ||
483 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
484 | "Connecting...\n"); | ||
485 | handle->gns = GNUNET_GNS_connect (cfg); | 303 | handle->gns = GNUNET_GNS_connect (cfg); |
486 | handle->identity = GNUNET_IDENTITY_connect (cfg, NULL, NULL); | ||
487 | handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout, | ||
488 | &do_error, handle); | ||
489 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
490 | "Connected\n"); | ||
491 | if (NULL == handle->gns) | 304 | if (NULL == handle->gns) |
492 | { | 305 | { |
493 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 306 | handle->emsg = GNUNET_strdup ("GNS not available"); |
494 | "Connecting to GNS failed\n"); | ||
495 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 307 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
496 | return; | 308 | return; |
497 | } | 309 | } |
498 | GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_OPTIONS, | 310 | |
499 | strlen (GNUNET_REST_JSONAPI_GNS_OPTIONS), | 311 | handle->gns_lookup = GNUNET_GNS_lookup_with_tld (handle->gns, |
500 | &key); | 312 | handle->name, |
501 | handle->options = GNUNET_GNS_LO_DEFAULT; | 313 | handle->record_type, |
502 | if ( GNUNET_YES == | 314 | GNUNET_NO, |
503 | GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, | 315 | &handle_gns_response, |
504 | &key) ) | 316 | handle); |
505 | { | 317 | |
506 | handle->options = GNUNET_GNS_LO_DEFAULT;//TODO(char*) GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, | 318 | if (NULL == handle->gns_lookup) |
507 | //&key); | ||
508 | } | ||
509 | GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_RECORD_TYPE, | ||
510 | strlen (GNUNET_REST_JSONAPI_GNS_RECORD_TYPE), | ||
511 | &key); | ||
512 | if ( GNUNET_YES == | ||
513 | GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, | ||
514 | &key) ) | ||
515 | { | ||
516 | handle->type = GNUNET_GNSRECORD_typename_to_number | ||
517 | (GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, | ||
518 | &key)); | ||
519 | } | ||
520 | else | ||
521 | handle->type = GNUNET_GNSRECORD_TYPE_ANY; | ||
522 | |||
523 | GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_PKEY, | ||
524 | strlen (GNUNET_REST_JSONAPI_GNS_PKEY), | ||
525 | &key); | ||
526 | if ( GNUNET_YES == | ||
527 | GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, | ||
528 | &key) ) | ||
529 | { | ||
530 | handle->pkey_str = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, | ||
531 | &key); | ||
532 | GNUNET_assert (NULL != handle->pkey_str); | ||
533 | if (GNUNET_OK != | ||
534 | GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->pkey_str, | ||
535 | strlen(handle->pkey_str), | ||
536 | &(handle->pkey))) | ||
537 | { | ||
538 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
539 | return; | ||
540 | } | ||
541 | lookup_with_public_key (handle); | ||
542 | return; | ||
543 | } | ||
544 | GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_EGO, | ||
545 | strlen (GNUNET_REST_JSONAPI_GNS_EGO), | ||
546 | &key); | ||
547 | if ( GNUNET_YES == | ||
548 | GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, | ||
549 | &key) ) | ||
550 | { | 319 | { |
551 | handle->ego_str = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, | 320 | handle->emsg = GNUNET_strdup("GNS lookup failed"); |
552 | &key); | 321 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
553 | handle->el = GNUNET_IDENTITY_ego_lookup (cfg, | ||
554 | handle->ego_str, | ||
555 | &identity_zone_cb, | ||
556 | handle); | ||
557 | return; | 322 | return; |
558 | } | 323 | } |
559 | if ( (NULL != handle->name) && | ||
560 | (strlen (handle->name) > 4) && | ||
561 | (0 == strcmp (".zkey", | ||
562 | &handle->name[strlen (handle->name) - 4])) ) | ||
563 | { | ||
564 | GNUNET_CRYPTO_ecdsa_key_get_public | ||
565 | (GNUNET_CRYPTO_ecdsa_key_get_anonymous (), | ||
566 | &(handle->pkey)); | ||
567 | lookup_with_public_key (handle); | ||
568 | } | ||
569 | else | ||
570 | { | ||
571 | GNUNET_break (NULL == handle->id_op); | ||
572 | handle->id_op = GNUNET_IDENTITY_get (handle->identity, | ||
573 | "gns-master", | ||
574 | &identity_master_cb, | ||
575 | handle); | ||
576 | GNUNET_assert (NULL != handle->id_op); | ||
577 | } | ||
578 | } | 324 | } |
579 | 325 | ||
326 | |||
327 | |||
580 | /** | 328 | /** |
581 | * Handle rest request | 329 | * Respond to OPTIONS request |
582 | * | 330 | * |
583 | * @param handle the lookup handle | 331 | * @param con_handle the connection handle |
332 | * @param url the url | ||
333 | * @param cls the RequestHandle | ||
584 | */ | 334 | */ |
585 | static void | 335 | static void |
586 | options_cont (struct GNUNET_REST_RequestHandle *con_handle, | 336 | options_cont (struct GNUNET_REST_RequestHandle *con_handle, |
@@ -588,53 +338,38 @@ options_cont (struct GNUNET_REST_RequestHandle *con_handle, | |||
588 | void *cls) | 338 | void *cls) |
589 | { | 339 | { |
590 | struct MHD_Response *resp; | 340 | struct MHD_Response *resp; |
591 | struct LookupHandle *handle = cls; | 341 | struct RequestHandle *handle = cls; |
592 | 342 | ||
593 | //For GNS, independent of path return all options | 343 | //independent of path return all options |
594 | resp = GNUNET_REST_create_response (NULL); | 344 | resp = GNUNET_REST_create_response (NULL); |
595 | MHD_add_response_header (resp, | 345 | MHD_add_response_header (resp, |
596 | "Access-Control-Allow-Methods", | 346 | "Access-Control-Allow-Methods", |
597 | MHD_HTTP_METHOD_GET); | 347 | allow_methods); |
598 | handle->proc (handle->proc_cls, | 348 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); |
599 | resp, | ||
600 | MHD_HTTP_OK); | ||
601 | cleanup_handle (handle); | 349 | cleanup_handle (handle); |
350 | return; | ||
602 | } | 351 | } |
603 | 352 | ||
604 | 353 | ||
605 | /** | 354 | /** |
606 | * Function processing the REST call | 355 | * Handle rest request |
607 | * | 356 | * |
608 | * @param method HTTP method | 357 | * @param handle the request handle |
609 | * @param url URL of the HTTP request | ||
610 | * @param data body of the HTTP request (optional) | ||
611 | * @param data_size length of the body | ||
612 | * @param proc callback function for the result | ||
613 | * @param proc_cls closure for @a proc | ||
614 | * @return #GNUNET_OK if request accepted | ||
615 | */ | 358 | */ |
616 | static void | 359 | static void |
617 | rest_gns_process_request (struct GNUNET_REST_RequestHandle *conndata_handle, | 360 | init_cont (struct RequestHandle *handle) |
618 | GNUNET_REST_ResultProcessor proc, | ||
619 | void *proc_cls) | ||
620 | { | 361 | { |
362 | struct GNUNET_REST_RequestHandlerError err; | ||
621 | static const struct GNUNET_REST_RequestHandler handlers[] = { | 363 | static const struct GNUNET_REST_RequestHandler handlers[] = { |
622 | {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_GNS, &get_gns_cont}, | 364 | {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_GNS, &get_gns_cont}, |
623 | {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_GNS, &options_cont}, | 365 | {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_GNS, &options_cont}, |
624 | GNUNET_REST_HANDLER_END | 366 | GNUNET_REST_HANDLER_END |
625 | }; | 367 | }; |
626 | struct LookupHandle *handle = GNUNET_new (struct LookupHandle); | ||
627 | struct GNUNET_REST_RequestHandlerError err; | ||
628 | 368 | ||
629 | handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; | 369 | if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, |
630 | handle->proc_cls = proc_cls; | 370 | handlers, |
631 | handle->proc = proc; | 371 | &err, |
632 | handle->rest_handle = conndata_handle; | 372 | handle)) |
633 | |||
634 | if (GNUNET_NO == GNUNET_JSONAPI_handle_request (conndata_handle, | ||
635 | handlers, | ||
636 | &err, | ||
637 | handle)) | ||
638 | { | 373 | { |
639 | handle->response_code = err.error_code; | 374 | handle->response_code = err.error_code; |
640 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 375 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
@@ -643,18 +378,58 @@ rest_gns_process_request (struct GNUNET_REST_RequestHandle *conndata_handle, | |||
643 | 378 | ||
644 | 379 | ||
645 | /** | 380 | /** |
381 | * Function processing the REST call | ||
382 | * | ||
383 | * @param method HTTP method | ||
384 | * @param url URL of the HTTP request | ||
385 | * @param data body of the HTTP request (optional) | ||
386 | * @param data_size length of the body | ||
387 | * @param proc callback function for the result | ||
388 | * @param proc_cls closure for callback function | ||
389 | * @return GNUNET_OK if request accepted | ||
390 | */ | ||
391 | static void | ||
392 | rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle, | ||
393 | GNUNET_REST_ResultProcessor proc, | ||
394 | void *proc_cls) | ||
395 | { | ||
396 | struct RequestHandle *handle = GNUNET_new (struct RequestHandle); | ||
397 | |||
398 | handle->response_code = 0; | ||
399 | handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; | ||
400 | handle->proc_cls = proc_cls; | ||
401 | handle->proc = proc; | ||
402 | handle->rest_handle = rest_handle; | ||
403 | |||
404 | handle->url = GNUNET_strdup (rest_handle->url); | ||
405 | if (handle->url[strlen (handle->url)-1] == '/') | ||
406 | handle->url[strlen (handle->url)-1] = '\0'; | ||
407 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); | ||
408 | |||
409 | init_cont(handle); | ||
410 | |||
411 | handle->timeout_task = | ||
412 | GNUNET_SCHEDULER_add_delayed (handle->timeout, | ||
413 | &do_error, | ||
414 | handle); | ||
415 | |||
416 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); | ||
417 | } | ||
418 | |||
419 | |||
420 | /** | ||
646 | * Entry point for the plugin. | 421 | * Entry point for the plugin. |
647 | * | 422 | * |
648 | * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*" | 423 | * @param cls Config info |
649 | * @return NULL on error, otherwise the plugin context | 424 | * @return NULL on error, otherwise the plugin context |
650 | */ | 425 | */ |
651 | void * | 426 | void * |
652 | libgnunet_plugin_rest_gns_init (void *cls) | 427 | libgnunet_plugin_rest_gns_init (void *cls) |
653 | { | 428 | { |
654 | static struct Plugin plugin; | 429 | static struct Plugin plugin; |
655 | cfg = cls; | ||
656 | struct GNUNET_REST_Plugin *api; | 430 | struct GNUNET_REST_Plugin *api; |
657 | 431 | ||
432 | cfg = cls; | ||
658 | if (NULL != plugin.cfg) | 433 | if (NULL != plugin.cfg) |
659 | return NULL; /* can only initialize once! */ | 434 | return NULL; /* can only initialize once! */ |
660 | memset (&plugin, 0, sizeof (struct Plugin)); | 435 | memset (&plugin, 0, sizeof (struct Plugin)); |
@@ -662,9 +437,17 @@ libgnunet_plugin_rest_gns_init (void *cls) | |||
662 | api = GNUNET_new (struct GNUNET_REST_Plugin); | 437 | api = GNUNET_new (struct GNUNET_REST_Plugin); |
663 | api->cls = &plugin; | 438 | api->cls = &plugin; |
664 | api->name = GNUNET_REST_API_NS_GNS; | 439 | api->name = GNUNET_REST_API_NS_GNS; |
665 | api->process_request = &rest_gns_process_request; | 440 | api->process_request = &rest_process_request; |
666 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 441 | GNUNET_asprintf (&allow_methods, |
667 | _("GNS REST API initialized\n")); | 442 | "%s, %s, %s, %s, %s", |
443 | MHD_HTTP_METHOD_GET, | ||
444 | MHD_HTTP_METHOD_POST, | ||
445 | MHD_HTTP_METHOD_PUT, | ||
446 | MHD_HTTP_METHOD_DELETE, | ||
447 | MHD_HTTP_METHOD_OPTIONS); | ||
448 | |||
449 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
450 | _("Gns REST API initialized\n")); | ||
668 | return api; | 451 | return api; |
669 | } | 452 | } |
670 | 453 | ||
@@ -680,12 +463,14 @@ libgnunet_plugin_rest_gns_done (void *cls) | |||
680 | { | 463 | { |
681 | struct GNUNET_REST_Plugin *api = cls; | 464 | struct GNUNET_REST_Plugin *api = cls; |
682 | struct Plugin *plugin = api->cls; | 465 | struct Plugin *plugin = api->cls; |
683 | |||
684 | plugin->cfg = NULL; | 466 | plugin->cfg = NULL; |
467 | |||
468 | GNUNET_free_non_null (allow_methods); | ||
685 | GNUNET_free (api); | 469 | GNUNET_free (api); |
686 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 470 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
687 | "GNS REST plugin is finished\n"); | 471 | "Gns REST plugin is finished\n"); |
688 | return NULL; | 472 | return NULL; |
689 | } | 473 | } |
690 | 474 | ||
691 | /* end of plugin_rest_gns.c */ | 475 | /* end of plugin_rest_gns.c */ |
476 | |||
diff --git a/src/gns/plugin_rest_gns2.c b/src/gns/plugin_rest_gns2.c new file mode 100644 index 000000000..82d62744c --- /dev/null +++ b/src/gns/plugin_rest_gns2.c | |||
@@ -0,0 +1,717 @@ | |||
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 gns/plugin_rest_gns.c | ||
22 | * @brief GNUnet GNS REST plugin | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include "platform.h" | ||
27 | #include "gnunet_rest_plugin.h" | ||
28 | #include <gnunet_dnsparser_lib.h> | ||
29 | #include <gnunet_identity_service.h> | ||
30 | #include <gnunet_gnsrecord_lib.h> | ||
31 | #include <gnunet_namestore_service.h> | ||
32 | #include <gnunet_gns_service.h> | ||
33 | #include <gnunet_rest_lib.h> | ||
34 | #include <gnunet_jsonapi_lib.h> | ||
35 | #include <gnunet_jsonapi_util.h> | ||
36 | #include <jansson.h> | ||
37 | |||
38 | #define GNUNET_REST_API_NS_GNS "/gns" | ||
39 | |||
40 | #define GNUNET_REST_JSONAPI_GNS_RECORD_TYPE "record_type" | ||
41 | |||
42 | #define GNUNET_REST_PARAMETER_GNS_NAME "name" | ||
43 | |||
44 | #define GNUNET_REST_JSONAPI_GNS_TYPEINFO "gns_name" | ||
45 | |||
46 | #define GNUNET_REST_JSONAPI_GNS_RECORD "records" | ||
47 | |||
48 | #define GNUNET_REST_JSONAPI_GNS_EGO "ego" | ||
49 | |||
50 | #define GNUNET_REST_JSONAPI_GNS_PKEY "pkey" | ||
51 | |||
52 | #define GNUNET_REST_JSONAPI_GNS_OPTIONS "options" | ||
53 | |||
54 | /** | ||
55 | * @brief struct returned by the initialization function of the plugin | ||
56 | */ | ||
57 | struct Plugin | ||
58 | { | ||
59 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
60 | }; | ||
61 | |||
62 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
63 | |||
64 | struct LookupHandle | ||
65 | { | ||
66 | /** | ||
67 | * Handle to GNS service. | ||
68 | */ | ||
69 | struct GNUNET_GNS_Handle *gns; | ||
70 | |||
71 | /** | ||
72 | * Desired timeout for the lookup (default is no timeout). | ||
73 | */ | ||
74 | struct GNUNET_TIME_Relative timeout; | ||
75 | |||
76 | /** | ||
77 | * Handle to lookup request | ||
78 | */ | ||
79 | struct GNUNET_GNS_LookupRequest *lookup_request; | ||
80 | |||
81 | /** | ||
82 | * Handle to rest request | ||
83 | */ | ||
84 | struct GNUNET_REST_RequestHandle *rest_handle; | ||
85 | |||
86 | /** | ||
87 | * Lookup an ego with the identity service. | ||
88 | */ | ||
89 | struct GNUNET_IDENTITY_EgoLookup *el; | ||
90 | |||
91 | /** | ||
92 | * Handle for identity service. | ||
93 | */ | ||
94 | struct GNUNET_IDENTITY_Handle *identity; | ||
95 | |||
96 | /** | ||
97 | * Active operation on identity service. | ||
98 | */ | ||
99 | struct GNUNET_IDENTITY_Operation *id_op; | ||
100 | |||
101 | /** | ||
102 | * ID of a task associated with the resolution process. | ||
103 | */ | ||
104 | struct GNUNET_SCHEDULER_Task * timeout_task; | ||
105 | |||
106 | /** | ||
107 | * The root of the received JSON or NULL | ||
108 | */ | ||
109 | json_t *json_root; | ||
110 | |||
111 | /** | ||
112 | * The plugin result processor | ||
113 | */ | ||
114 | GNUNET_REST_ResultProcessor proc; | ||
115 | |||
116 | /** | ||
117 | * The closure of the result processor | ||
118 | */ | ||
119 | void *proc_cls; | ||
120 | |||
121 | /** | ||
122 | * The name to look up | ||
123 | */ | ||
124 | char *name; | ||
125 | |||
126 | /** | ||
127 | * The ego to use | ||
128 | * In string representation from JSON | ||
129 | */ | ||
130 | const char *ego_str; | ||
131 | |||
132 | /** | ||
133 | * The Pkey to use | ||
134 | * In string representation from JSON | ||
135 | */ | ||
136 | const char *pkey_str; | ||
137 | |||
138 | /** | ||
139 | * The record type | ||
140 | */ | ||
141 | int type; | ||
142 | |||
143 | /** | ||
144 | * The public key of to use for lookup | ||
145 | */ | ||
146 | struct GNUNET_CRYPTO_EcdsaPublicKey pkey; | ||
147 | |||
148 | /** | ||
149 | * The public key to use for lookup | ||
150 | */ | ||
151 | struct GNUNET_CRYPTO_EcdsaPublicKey pkeym; | ||
152 | |||
153 | /** | ||
154 | * The resolver options | ||
155 | */ | ||
156 | enum GNUNET_GNS_LocalOptions options; | ||
157 | |||
158 | /** | ||
159 | * the shorten key | ||
160 | */ | ||
161 | struct GNUNET_CRYPTO_EcdsaPrivateKey shorten_key; | ||
162 | |||
163 | /** | ||
164 | * HTTP response code | ||
165 | */ | ||
166 | int response_code; | ||
167 | |||
168 | /** | ||
169 | * HTTP response code | ||
170 | */ | ||
171 | char* emsg; | ||
172 | |||
173 | }; | ||
174 | |||
175 | |||
176 | /** | ||
177 | * Cleanup lookup handle. | ||
178 | * | ||
179 | * @param handle Handle to clean up | ||
180 | */ | ||
181 | static void | ||
182 | cleanup_handle (struct LookupHandle *handle) | ||
183 | { | ||
184 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
185 | "Cleaning up\n"); | ||
186 | if (NULL != handle->json_root) | ||
187 | json_decref (handle->json_root); | ||
188 | |||
189 | if (NULL != handle->name) | ||
190 | GNUNET_free (handle->name); | ||
191 | if (NULL != handle->emsg) | ||
192 | GNUNET_free (handle->emsg); | ||
193 | if (NULL != handle->el) | ||
194 | { | ||
195 | GNUNET_IDENTITY_ego_lookup_cancel (handle->el); | ||
196 | handle->el = NULL; | ||
197 | } | ||
198 | if (NULL != handle->id_op) | ||
199 | { | ||
200 | GNUNET_IDENTITY_cancel (handle->id_op); | ||
201 | handle->id_op = NULL; | ||
202 | } | ||
203 | if (NULL != handle->lookup_request) | ||
204 | { | ||
205 | GNUNET_GNS_lookup_cancel (handle->lookup_request); | ||
206 | handle->lookup_request = NULL; | ||
207 | } | ||
208 | if (NULL != handle->identity) | ||
209 | { | ||
210 | GNUNET_IDENTITY_disconnect (handle->identity); | ||
211 | handle->identity = NULL; | ||
212 | } | ||
213 | if (NULL != handle->gns) | ||
214 | { | ||
215 | GNUNET_GNS_disconnect (handle->gns); | ||
216 | handle->gns = NULL; | ||
217 | } | ||
218 | |||
219 | if (NULL != handle->timeout_task) | ||
220 | { | ||
221 | GNUNET_SCHEDULER_cancel (handle->timeout_task); | ||
222 | } | ||
223 | GNUNET_free (handle); | ||
224 | } | ||
225 | |||
226 | |||
227 | /** | ||
228 | * Task run on shutdown. Cleans up everything. | ||
229 | * | ||
230 | * @param cls unused | ||
231 | * @param tc scheduler context | ||
232 | */ | ||
233 | static void | ||
234 | do_error (void *cls) | ||
235 | { | ||
236 | struct LookupHandle *handle = cls; | ||
237 | struct MHD_Response *resp; | ||
238 | char *json_error; | ||
239 | |||
240 | if (NULL == handle->emsg) | ||
241 | handle->emsg = GNUNET_strdup("Unknown Error"); | ||
242 | |||
243 | GNUNET_asprintf (&json_error, "{\"error\": \"%s\"}", handle->emsg); | ||
244 | handle->response_code = MHD_HTTP_OK; | ||
245 | |||
246 | resp = GNUNET_REST_create_response (json_error); | ||
247 | handle->proc (handle->proc_cls, resp, handle->response_code); | ||
248 | cleanup_handle (handle); | ||
249 | GNUNET_free(json_error); | ||
250 | } | ||
251 | |||
252 | |||
253 | /** | ||
254 | * Create json representation of a GNSRECORD | ||
255 | * | ||
256 | * @param rd the GNSRECORD_Data | ||
257 | */ | ||
258 | static json_t * | ||
259 | gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd) | ||
260 | { | ||
261 | const char *typename; | ||
262 | char *string_val; | ||
263 | const char *exp_str; | ||
264 | json_t *record_obj; | ||
265 | |||
266 | typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type); | ||
267 | string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type, | ||
268 | rd->data, | ||
269 | rd->data_size); | ||
270 | |||
271 | if (NULL == string_val) | ||
272 | { | ||
273 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
274 | "Record of type %d malformed, skipping\n", | ||
275 | (int) rd->record_type); | ||
276 | return NULL; | ||
277 | } | ||
278 | record_obj = json_object (); | ||
279 | json_object_set_new (record_obj, "type", json_string (typename)); | ||
280 | json_object_set_new (record_obj, "value", json_string (string_val)); | ||
281 | GNUNET_free (string_val); | ||
282 | |||
283 | if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags) | ||
284 | { | ||
285 | struct GNUNET_TIME_Relative time_rel; | ||
286 | time_rel.rel_value_us = rd->expiration_time; | ||
287 | exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1); | ||
288 | } | ||
289 | else | ||
290 | { | ||
291 | struct GNUNET_TIME_Absolute time_abs; | ||
292 | time_abs.abs_value_us = rd->expiration_time; | ||
293 | exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs); | ||
294 | } | ||
295 | json_object_set_new (record_obj, "expiration_time", json_string (exp_str)); | ||
296 | |||
297 | json_object_set_new (record_obj, "expired", | ||
298 | json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd))); | ||
299 | return record_obj; | ||
300 | } | ||
301 | |||
302 | /** | ||
303 | * Function called with the result of a GNS lookup. | ||
304 | * | ||
305 | * @param cls the 'const char *' name that was resolved | ||
306 | * @param rd_count number of records returned | ||
307 | * @param rd array of @a rd_count records with the results | ||
308 | */ | ||
309 | static void | ||
310 | process_lookup_result (void *cls, uint32_t rd_count, | ||
311 | const struct GNUNET_GNSRECORD_Data *rd) | ||
312 | { | ||
313 | struct LookupHandle *handle = cls; | ||
314 | struct MHD_Response *resp; | ||
315 | uint32_t i; | ||
316 | char *result; | ||
317 | json_t *result_array; | ||
318 | json_t *record_obj; | ||
319 | |||
320 | result_array = json_array(); | ||
321 | handle->lookup_request = NULL; | ||
322 | for (i=0; i<rd_count; i++) | ||
323 | { | ||
324 | if ( (rd[i].record_type != handle->type) && | ||
325 | (GNUNET_GNSRECORD_TYPE_ANY != handle->type) ) | ||
326 | continue; | ||
327 | record_obj = gnsrecord_to_json (&(rd[i])); | ||
328 | json_array_append (result_array, record_obj); | ||
329 | json_decref (record_obj); | ||
330 | } | ||
331 | result = json_dumps(result_array, 0); | ||
332 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result); | ||
333 | resp = GNUNET_REST_create_response (result); | ||
334 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); | ||
335 | GNUNET_free (result); | ||
336 | json_decref (result_array); | ||
337 | cleanup_handle (handle); | ||
338 | } | ||
339 | |||
340 | |||
341 | /** | ||
342 | * Perform the actual resolution, starting with the zone | ||
343 | * identified by the given public key and the shorten zone. | ||
344 | * | ||
345 | * @param pkey public key to use for the zone, can be NULL | ||
346 | */ | ||
347 | static void | ||
348 | lookup_with_public_key (struct LookupHandle *handle) | ||
349 | { | ||
350 | if (UINT32_MAX == handle->type) | ||
351 | { | ||
352 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
353 | _("Invalid typename specified, assuming `ANY'\n")); | ||
354 | handle->type = GNUNET_GNSRECORD_TYPE_ANY; | ||
355 | } | ||
356 | if (NULL != handle->name) | ||
357 | { | ||
358 | handle->lookup_request = GNUNET_GNS_lookup (handle->gns, | ||
359 | handle->name, | ||
360 | &handle->pkey, | ||
361 | handle->type, | ||
362 | handle->options, | ||
363 | &process_lookup_result, | ||
364 | handle); | ||
365 | } | ||
366 | else | ||
367 | { | ||
368 | handle->emsg = GNUNET_strdup("Parameter name is missing"); | ||
369 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
370 | return; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | |||
375 | /** | ||
376 | * Method called to with the ego we are to use for the lookup, | ||
377 | * when the ego is determined by a name. | ||
378 | * | ||
379 | * @param cls closure (NULL, unused) | ||
380 | * @param ego ego handle, NULL if not found | ||
381 | */ | ||
382 | static void | ||
383 | identity_zone_cb (void *cls, | ||
384 | const struct GNUNET_IDENTITY_Ego *ego) | ||
385 | { | ||
386 | struct LookupHandle *handle = cls; | ||
387 | |||
388 | handle->el = NULL; | ||
389 | if (NULL == ego) | ||
390 | { | ||
391 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
392 | _("Ego for not found, cannot perform lookup.\n")); | ||
393 | handle->emsg = GNUNET_strdup ("Ego for not found, cannot perform lookup."); | ||
394 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
395 | return; | ||
396 | } | ||
397 | else | ||
398 | { | ||
399 | GNUNET_IDENTITY_ego_get_public_key (ego, &handle->pkey); | ||
400 | lookup_with_public_key (handle); | ||
401 | } | ||
402 | json_decref(handle->json_root); | ||
403 | } | ||
404 | |||
405 | |||
406 | /** | ||
407 | * Method called to with the ego we are to use for the lookup, | ||
408 | * when the ego is the one for the default master zone. | ||
409 | * | ||
410 | * @param cls closure (NULL, unused) | ||
411 | * @param ego ego handle, NULL if not found | ||
412 | * @param ctx context for application to store data for this ego | ||
413 | * (during the lifetime of this process, initially NULL) | ||
414 | * @param name name assigned by the user for this ego, | ||
415 | * NULL if the user just deleted the ego and it | ||
416 | * must thus no longer be used | ||
417 | */ | ||
418 | static void | ||
419 | identity_master_cb (void *cls, | ||
420 | struct GNUNET_IDENTITY_Ego *ego, | ||
421 | void **ctx, | ||
422 | const char *name) | ||
423 | { | ||
424 | const char *dot; | ||
425 | struct LookupHandle *handle = cls; | ||
426 | |||
427 | handle->id_op = NULL; | ||
428 | if (NULL == ego) | ||
429 | { | ||
430 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
431 | _("Ego for `gns-master' not found, cannot perform lookup. Did you run gnunet-gns-import.sh?\n")); | ||
432 | handle->emsg = GNUNET_strdup("Ego for `gns-master' not found, cannot perform lookup. Did you run gnunet-gns-import.sh?"); | ||
433 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
434 | return; | ||
435 | } | ||
436 | GNUNET_IDENTITY_ego_get_public_key (ego, | ||
437 | &handle->pkey); | ||
438 | /* main name is our own master zone, do no look for that in the DHT */ | ||
439 | handle->options = GNUNET_GNS_LO_LOCAL_MASTER; | ||
440 | /* if the name is of the form 'label.gnu', never go to the DHT */ | ||
441 | dot = NULL; | ||
442 | if (NULL != handle->name) | ||
443 | dot = strchr (handle->name, '.'); | ||
444 | if ( (NULL != dot) && | ||
445 | (0 == strcasecmp (dot, ".gnu")) ) | ||
446 | handle->options = GNUNET_GNS_LO_NO_DHT; | ||
447 | lookup_with_public_key (handle); | ||
448 | } | ||
449 | |||
450 | /** | ||
451 | * Handle get request | ||
452 | * | ||
453 | * @param handle the lookup handle | ||
454 | */ | ||
455 | static void | ||
456 | get_gns_cont (struct GNUNET_REST_RequestHandle *conndata_handle, | ||
457 | const char* url, | ||
458 | void *cls) | ||
459 | { | ||
460 | struct LookupHandle *handle = cls; | ||
461 | struct GNUNET_HashCode key; | ||
462 | long int enum_test; | ||
463 | char *temp_val; | ||
464 | |||
465 | //check for /gns otherwise 404 | ||
466 | if (strlen (GNUNET_REST_API_NS_GNS) > strlen (url)) | ||
467 | { | ||
468 | handle->emsg = GNUNET_strdup("Wrong URL"); | ||
469 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
470 | return; | ||
471 | } | ||
472 | |||
473 | //connect to gns | ||
474 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); | ||
475 | handle->gns = GNUNET_GNS_connect (cfg); | ||
476 | handle->identity = GNUNET_IDENTITY_connect (cfg, NULL, NULL); | ||
477 | handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout, | ||
478 | &do_error, handle); | ||
479 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); | ||
480 | if (NULL == handle->gns) | ||
481 | { | ||
482 | GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Connecting to GNS failed\n"); | ||
483 | handle->emsg = GNUNET_strdup("Connecting to GNS failed"); | ||
484 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
485 | return; | ||
486 | } | ||
487 | |||
488 | //check parameter name -> BAD_REQUEST | ||
489 | GNUNET_CRYPTO_hash (GNUNET_REST_PARAMETER_GNS_NAME, | ||
490 | strlen (GNUNET_REST_PARAMETER_GNS_NAME), | ||
491 | &key); | ||
492 | if ( GNUNET_NO | ||
493 | == GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, | ||
494 | &key)) | ||
495 | { | ||
496 | handle->emsg = GNUNET_strdup("Parameter name is missing"); | ||
497 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
498 | return; | ||
499 | } | ||
500 | handle->name = GNUNET_strdup(GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, | ||
501 | &key)); | ||
502 | |||
503 | //check parameter record_type, optional | ||
504 | GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_RECORD_TYPE, | ||
505 | strlen (GNUNET_REST_JSONAPI_GNS_RECORD_TYPE), | ||
506 | &key); | ||
507 | if ( GNUNET_YES == | ||
508 | GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, | ||
509 | &key) ) | ||
510 | { | ||
511 | handle->type = GNUNET_GNSRECORD_typename_to_number( | ||
512 | GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, | ||
513 | &key)); | ||
514 | } | ||
515 | else | ||
516 | { | ||
517 | handle->type = GNUNET_GNSRECORD_TYPE_ANY; | ||
518 | } | ||
519 | |||
520 | //check parameter options, optional | ||
521 | GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_OPTIONS, | ||
522 | strlen (GNUNET_REST_JSONAPI_GNS_OPTIONS), | ||
523 | &key); | ||
524 | handle->options = GNUNET_GNS_LO_DEFAULT; | ||
525 | if ( GNUNET_YES | ||
526 | == GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, | ||
527 | &key)) | ||
528 | { | ||
529 | temp_val = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, &key); | ||
530 | if (1 < strlen(temp_val)) | ||
531 | { | ||
532 | handle->options = GNUNET_GNS_LO_DEFAULT; | ||
533 | } | ||
534 | else | ||
535 | { | ||
536 | //atoi because no valid conversion is default local option | ||
537 | enum_test = atoi(temp_val); | ||
538 | if (2 < enum_test) | ||
539 | handle->options = GNUNET_GNS_LO_DEFAULT; | ||
540 | else | ||
541 | handle->options = enum_test; | ||
542 | } | ||
543 | } | ||
544 | else | ||
545 | handle->options = GNUNET_GNS_LO_DEFAULT; | ||
546 | |||
547 | //check parameter pkey, shortcut to lookup | ||
548 | GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_PKEY, | ||
549 | strlen (GNUNET_REST_JSONAPI_GNS_PKEY), | ||
550 | &key); | ||
551 | if ( GNUNET_YES | ||
552 | == GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, | ||
553 | &key)) | ||
554 | { | ||
555 | handle->pkey_str = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, | ||
556 | &key); | ||
557 | GNUNET_assert(NULL != handle->pkey_str); | ||
558 | if (GNUNET_OK | ||
559 | != GNUNET_CRYPTO_ecdsa_public_key_from_string ( | ||
560 | handle->pkey_str, strlen (handle->pkey_str), &(handle->pkey))) | ||
561 | { | ||
562 | handle->emsg = GNUNET_strdup("Parameter pkey has a wrong format"); | ||
563 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
564 | return; | ||
565 | } | ||
566 | lookup_with_public_key (handle); | ||
567 | return; | ||
568 | } | ||
569 | |||
570 | //check parameter ego, lookup public key of ego | ||
571 | GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_EGO, | ||
572 | strlen (GNUNET_REST_JSONAPI_GNS_EGO), | ||
573 | &key); | ||
574 | if ( GNUNET_YES == | ||
575 | GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, | ||
576 | &key) ) | ||
577 | { | ||
578 | handle->ego_str = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, | ||
579 | &key); | ||
580 | handle->el = GNUNET_IDENTITY_ego_lookup (cfg, | ||
581 | handle->ego_str, | ||
582 | &identity_zone_cb, | ||
583 | handle); | ||
584 | return; | ||
585 | } | ||
586 | |||
587 | //if name ends with .zkey then get public key | ||
588 | if ( (NULL != handle->name) && | ||
589 | (strlen (handle->name) > 4) && | ||
590 | (0 == strcmp (".zkey", | ||
591 | &handle->name[strlen (handle->name) - 4])) ) | ||
592 | { | ||
593 | GNUNET_CRYPTO_ecdsa_key_get_public( GNUNET_CRYPTO_ecdsa_key_get_anonymous (), | ||
594 | &(handle->pkey)); | ||
595 | lookup_with_public_key (handle); | ||
596 | } | ||
597 | else //else use gns-master identity | ||
598 | { | ||
599 | handle->id_op = GNUNET_IDENTITY_get (handle->identity, | ||
600 | "gns-master", | ||
601 | &identity_master_cb, | ||
602 | handle); | ||
603 | } | ||
604 | } | ||
605 | |||
606 | /** | ||
607 | * Handle rest request | ||
608 | * | ||
609 | * @param handle the lookup handle | ||
610 | */ | ||
611 | static void | ||
612 | options_cont (struct GNUNET_REST_RequestHandle *con_handle, | ||
613 | const char* url, | ||
614 | void *cls) | ||
615 | { | ||
616 | struct MHD_Response *resp; | ||
617 | struct LookupHandle *handle = cls; | ||
618 | |||
619 | //For GNS, independent of path return all options | ||
620 | resp = GNUNET_REST_create_response (NULL); | ||
621 | MHD_add_response_header (resp, | ||
622 | "Access-Control-Allow-Methods", | ||
623 | MHD_HTTP_METHOD_GET); | ||
624 | handle->proc (handle->proc_cls, | ||
625 | resp, | ||
626 | MHD_HTTP_OK); | ||
627 | cleanup_handle (handle); | ||
628 | } | ||
629 | |||
630 | |||
631 | /** | ||
632 | * Function processing the REST call | ||
633 | * | ||
634 | * @param method HTTP method | ||
635 | * @param url URL of the HTTP request | ||
636 | * @param data body of the HTTP request (optional) | ||
637 | * @param data_size length of the body | ||
638 | * @param proc callback function for the result | ||
639 | * @param proc_cls closure for @a proc | ||
640 | * @return #GNUNET_OK if request accepted | ||
641 | */ | ||
642 | static void | ||
643 | rest_gns_process_request (struct GNUNET_REST_RequestHandle *conndata_handle, | ||
644 | GNUNET_REST_ResultProcessor proc, | ||
645 | void *proc_cls) | ||
646 | { | ||
647 | static const struct GNUNET_REST_RequestHandler handlers[] = { | ||
648 | {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_GNS, &get_gns_cont}, | ||
649 | {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_GNS, &options_cont}, | ||
650 | GNUNET_REST_HANDLER_END | ||
651 | }; | ||
652 | struct LookupHandle *handle = GNUNET_new (struct LookupHandle); | ||
653 | struct GNUNET_REST_RequestHandlerError err; | ||
654 | |||
655 | handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; | ||
656 | handle->proc_cls = proc_cls; | ||
657 | handle->proc = proc; | ||
658 | handle->rest_handle = conndata_handle; | ||
659 | |||
660 | if (GNUNET_NO == GNUNET_REST_handle_request (conndata_handle, | ||
661 | handlers, | ||
662 | &err, | ||
663 | handle)) | ||
664 | { | ||
665 | handle->response_code = err.error_code; | ||
666 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
667 | } | ||
668 | } | ||
669 | |||
670 | |||
671 | /** | ||
672 | * Entry point for the plugin. | ||
673 | * | ||
674 | * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*" | ||
675 | * @return NULL on error, otherwise the plugin context | ||
676 | */ | ||
677 | void * | ||
678 | libgnunet_plugin_rest_gns_init (void *cls) | ||
679 | { | ||
680 | static struct Plugin plugin; | ||
681 | cfg = cls; | ||
682 | struct GNUNET_REST_Plugin *api; | ||
683 | |||
684 | if (NULL != plugin.cfg) | ||
685 | return NULL; /* can only initialize once! */ | ||
686 | memset (&plugin, 0, sizeof (struct Plugin)); | ||
687 | plugin.cfg = cfg; | ||
688 | api = GNUNET_new (struct GNUNET_REST_Plugin); | ||
689 | api->cls = &plugin; | ||
690 | api->name = GNUNET_REST_API_NS_GNS; | ||
691 | api->process_request = &rest_gns_process_request; | ||
692 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
693 | _("GNS REST API initialized\n")); | ||
694 | return api; | ||
695 | } | ||
696 | |||
697 | |||
698 | /** | ||
699 | * Exit point from the plugin. | ||
700 | * | ||
701 | * @param cls the plugin context (as returned by "init") | ||
702 | * @return always NULL | ||
703 | */ | ||
704 | void * | ||
705 | libgnunet_plugin_rest_gns_done (void *cls) | ||
706 | { | ||
707 | struct GNUNET_REST_Plugin *api = cls; | ||
708 | struct Plugin *plugin = api->cls; | ||
709 | |||
710 | plugin->cfg = NULL; | ||
711 | GNUNET_free (api); | ||
712 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
713 | "GNS REST plugin is finished\n"); | ||
714 | return NULL; | ||
715 | } | ||
716 | |||
717 | /* end of plugin_rest_gns.c */ | ||
diff --git a/src/identity/plugin_rest_identity.c b/src/identity/plugin_rest_identity.c index 52685c52e..8d525b950 100644 --- a/src/identity/plugin_rest_identity.c +++ b/src/identity/plugin_rest_identity.c | |||
@@ -1,84 +1,63 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2012-2015 GNUnet e.V. | 3 | Copyright (C) 2012-2015 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software: you can redistribute it and/or modify it | 5 | GNUnet is free software; you can redistribute it and/or modify |
6 | under the terms of the GNU Affero General Public License as published | 6 | it under the terms of the GNU General Public License as published |
7 | by the Free Software Foundation, either version 3 of the License, | 7 | by the Free Software Foundation; either version 3, or (at your |
8 | or (at your option) any later version. | 8 | option) any later version. |
9 | 9 | ||
10 | GNUnet is distributed in the hope that it will be useful, but | 10 | GNUnet is distributed in the hope that it will be useful, but |
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Affero General Public License for more details. | 13 | General Public License for more details. |
14 | 14 | ||
15 | You should have received a copy of the GNU Affero General Public License | 15 | You should have received a copy of the GNU General Public License |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 16 | along with GNUnet; see the file COPYING. If not, write to the |
17 | */ | 17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
18 | /** | 20 | /** |
19 | * @author Martin Schanzenbach | 21 | * @author Martin Schanzenbach |
22 | * @author Philippe Buschmann | ||
20 | * @file identity/plugin_rest_identity.c | 23 | * @file identity/plugin_rest_identity.c |
21 | * @brief GNUnet Namestore REST plugin | 24 | * @brief GNUnet Identity REST plugin |
22 | * | ||
23 | */ | 25 | */ |
24 | 26 | ||
25 | #include "platform.h" | 27 | #include "platform.h" |
26 | #include "gnunet_rest_plugin.h" | 28 | #include "gnunet_rest_plugin.h" |
27 | #include "gnunet_identity_service.h" | 29 | #include "gnunet_identity_service.h" |
28 | #include "gnunet_rest_lib.h" | 30 | #include "gnunet_rest_lib.h" |
29 | #include "gnunet_jsonapi_lib.h" | ||
30 | #include "gnunet_jsonapi_util.h" | ||
31 | #include "microhttpd.h" | 31 | #include "microhttpd.h" |
32 | #include <jansson.h> | 32 | #include <jansson.h> |
33 | #include "gnunet_signatures.h" | ||
34 | 33 | ||
35 | /** | ||
36 | * REST root namespace | ||
37 | */ | ||
38 | #define GNUNET_REST_API_NS_IDENTITY "/identity" | 34 | #define GNUNET_REST_API_NS_IDENTITY "/identity" |
39 | 35 | ||
40 | /** | 36 | /** |
41 | * State while collecting all egos | 37 | * Parameter names |
42 | */ | 38 | */ |
43 | #define ID_REST_STATE_INIT 0 | 39 | #define GNUNET_REST_PARAM_PUBKEY "pubkey" |
44 | 40 | #define GNUNET_REST_PARAM_SUBSYSTEM "subsystem" | |
45 | /** | 41 | #define GNUNET_REST_PARAM_NAME "name" |
46 | * Done collecting egos | 42 | #define GNUNET_REST_PARAM_NEWNAME "newname" |
47 | */ | ||
48 | #define ID_REST_STATE_POST_INIT 1 | ||
49 | |||
50 | /** | ||
51 | * Resource type | ||
52 | */ | ||
53 | #define GNUNET_REST_JSONAPI_IDENTITY_EGO "ego" | ||
54 | |||
55 | /** | ||
56 | * Name attribute | ||
57 | */ | ||
58 | #define GNUNET_REST_JSONAPI_IDENTITY_NAME "name" | ||
59 | |||
60 | /** | ||
61 | * Attribute to rename "name" TODO we changed id to the pubkey | ||
62 | * so this can be unified with "name" | ||
63 | */ | ||
64 | #define GNUNET_REST_JSONAPI_IDENTITY_NEWNAME "newname" | ||
65 | |||
66 | /** | ||
67 | * URL parameter to change the subsytem for ego | ||
68 | */ | ||
69 | #define GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM "subsystem" | ||
70 | |||
71 | 43 | ||
72 | /** | 44 | /** |
73 | * Error messages | 45 | * Error messages |
74 | */ | 46 | */ |
47 | #define GNUNET_REST_ERROR_UNKNOWN "Unknown Error" | ||
75 | #define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid" | 48 | #define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid" |
76 | #define GNUNET_REST_ERROR_NO_DATA "No data" | 49 | #define GNUNET_REST_ERROR_NO_DATA "No data" |
50 | #define GNUNET_REST_ERROR_DATA_INVALID "Data invalid" | ||
51 | |||
52 | /** | ||
53 | * State while collecting all egos | ||
54 | */ | ||
55 | #define ID_REST_STATE_INIT 0 | ||
77 | 56 | ||
78 | /** | 57 | /** |
79 | * GNUid token lifetime | 58 | * Done collecting egos |
80 | */ | 59 | */ |
81 | #define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000 | 60 | #define ID_REST_STATE_POST_INIT 1 |
82 | 61 | ||
83 | /** | 62 | /** |
84 | * The configuration handle | 63 | * The configuration handle |
@@ -129,28 +108,37 @@ struct EgoEntry | |||
129 | struct GNUNET_IDENTITY_Ego *ego; | 108 | struct GNUNET_IDENTITY_Ego *ego; |
130 | }; | 109 | }; |
131 | 110 | ||
132 | |||
133 | struct RequestHandle | 111 | struct RequestHandle |
134 | { | 112 | { |
135 | /** | 113 | /** |
136 | * Ego list | 114 | * The data from the REST request |
137 | */ | 115 | */ |
138 | struct EgoEntry *ego_head; | 116 | const char* data; |
139 | 117 | ||
140 | /** | 118 | /** |
141 | * Ego list | 119 | * The name to look up |
142 | */ | 120 | */ |
143 | struct EgoEntry *ego_tail; | 121 | char *name; |
144 | 122 | ||
145 | /** | 123 | /** |
146 | * Handle to the rest connection | 124 | * the length of the REST data |
147 | */ | 125 | */ |
148 | struct GNUNET_REST_RequestHandle *conndata_handle; | 126 | size_t data_size; |
149 | 127 | ||
150 | /** | 128 | /** |
151 | * response code | 129 | * Requested Subsystem |
152 | */ | 130 | */ |
153 | int response_code; | 131 | char *subsystem; |
132 | |||
133 | /** | ||
134 | * Ego list | ||
135 | */ | ||
136 | struct EgoEntry *ego_head; | ||
137 | |||
138 | /** | ||
139 | * Ego list | ||
140 | */ | ||
141 | struct EgoEntry *ego_tail; | ||
154 | 142 | ||
155 | /** | 143 | /** |
156 | * The processing state | 144 | * The processing state |
@@ -158,7 +146,7 @@ struct RequestHandle | |||
158 | int state; | 146 | int state; |
159 | 147 | ||
160 | /** | 148 | /** |
161 | * Handle to GNS service. | 149 | * Handle to Identity service. |
162 | */ | 150 | */ |
163 | struct GNUNET_IDENTITY_Handle *identity_handle; | 151 | struct GNUNET_IDENTITY_Handle *identity_handle; |
164 | 152 | ||
@@ -168,6 +156,11 @@ struct RequestHandle | |||
168 | struct GNUNET_IDENTITY_Operation *op; | 156 | struct GNUNET_IDENTITY_Operation *op; |
169 | 157 | ||
170 | /** | 158 | /** |
159 | * Rest connection | ||
160 | */ | ||
161 | struct GNUNET_REST_RequestHandle *rest_handle; | ||
162 | |||
163 | /** | ||
171 | * Desired timeout for the lookup (default is no timeout). | 164 | * Desired timeout for the lookup (default is no timeout). |
172 | */ | 165 | */ |
173 | struct GNUNET_TIME_Relative timeout; | 166 | struct GNUNET_TIME_Relative timeout; |
@@ -175,7 +168,7 @@ struct RequestHandle | |||
175 | /** | 168 | /** |
176 | * ID of a task associated with the resolution process. | 169 | * ID of a task associated with the resolution process. |
177 | */ | 170 | */ |
178 | struct GNUNET_SCHEDULER_Task * timeout_task; | 171 | struct GNUNET_SCHEDULER_Task *timeout_task; |
179 | 172 | ||
180 | /** | 173 | /** |
181 | * The plugin result processor | 174 | * The plugin result processor |
@@ -188,43 +181,22 @@ struct RequestHandle | |||
188 | void *proc_cls; | 181 | void *proc_cls; |
189 | 182 | ||
190 | /** | 183 | /** |
191 | * The name to look up | ||
192 | */ | ||
193 | char *name; | ||
194 | |||
195 | /** | ||
196 | * The subsystem set from REST | ||
197 | */ | ||
198 | char *subsys; | ||
199 | |||
200 | /** | ||
201 | * The url | 184 | * The url |
202 | */ | 185 | */ |
203 | char *url; | 186 | char *url; |
204 | 187 | ||
205 | /** | 188 | /** |
206 | * The data from the REST request | 189 | * Error response message |
207 | */ | ||
208 | const char* data; | ||
209 | |||
210 | /** | ||
211 | * the length of the REST data | ||
212 | */ | ||
213 | size_t data_size; | ||
214 | |||
215 | /** | ||
216 | * HTTP method | ||
217 | */ | 190 | */ |
218 | const char* method; | 191 | char *emsg; |
219 | 192 | ||
220 | /** | 193 | /** |
221 | * Error response message | 194 | * Reponse code |
222 | */ | 195 | */ |
223 | char *emsg; | 196 | int response_code; |
224 | 197 | ||
225 | }; | 198 | }; |
226 | 199 | ||
227 | |||
228 | /** | 200 | /** |
229 | * Cleanup lookup handle | 201 | * Cleanup lookup handle |
230 | * @param handle Handle to clean up | 202 | * @param handle Handle to clean up |
@@ -234,35 +206,37 @@ cleanup_handle (struct RequestHandle *handle) | |||
234 | { | 206 | { |
235 | struct EgoEntry *ego_entry; | 207 | struct EgoEntry *ego_entry; |
236 | struct EgoEntry *ego_tmp; | 208 | struct EgoEntry *ego_tmp; |
237 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 209 | |
238 | "Cleaning up\n"); | 210 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); |
239 | if (NULL != handle->name) | ||
240 | GNUNET_free (handle->name); | ||
241 | if (NULL != handle->timeout_task) | 211 | if (NULL != handle->timeout_task) |
242 | { | 212 | { |
243 | GNUNET_SCHEDULER_cancel (handle->timeout_task); | 213 | GNUNET_SCHEDULER_cancel (handle->timeout_task); |
244 | handle->timeout_task = NULL; | 214 | handle->timeout_task = NULL; |
245 | } | 215 | } |
246 | if (NULL != handle->identity_handle) | 216 | |
247 | GNUNET_IDENTITY_disconnect (handle->identity_handle); | 217 | if (NULL != handle->subsystem) |
248 | if (NULL != handle->subsys) | 218 | GNUNET_free(handle->subsystem); |
249 | GNUNET_free (handle->subsys); | ||
250 | if (NULL != handle->url) | 219 | if (NULL != handle->url) |
251 | GNUNET_free (handle->url); | 220 | GNUNET_free(handle->url); |
252 | if (NULL != handle->emsg) | 221 | if (NULL != handle->emsg) |
253 | GNUNET_free (handle->emsg); | 222 | GNUNET_free(handle->emsg); |
223 | if (NULL != handle->name) | ||
224 | GNUNET_free (handle->name); | ||
225 | if (NULL != handle->identity_handle) | ||
226 | GNUNET_IDENTITY_disconnect (handle->identity_handle); | ||
227 | |||
254 | for (ego_entry = handle->ego_head; | 228 | for (ego_entry = handle->ego_head; |
255 | NULL != ego_entry;) | 229 | NULL != ego_entry;) |
256 | { | 230 | { |
257 | ego_tmp = ego_entry; | 231 | ego_tmp = ego_entry; |
258 | ego_entry = ego_entry->next; | 232 | ego_entry = ego_entry->next; |
259 | GNUNET_free (ego_tmp->identifier); | 233 | GNUNET_free(ego_tmp->identifier); |
260 | GNUNET_free (ego_tmp->keystring); | 234 | GNUNET_free(ego_tmp->keystring); |
261 | GNUNET_free (ego_tmp); | 235 | GNUNET_free(ego_tmp); |
262 | } | 236 | } |
263 | GNUNET_free (handle); | ||
264 | } | ||
265 | 237 | ||
238 | GNUNET_free(handle); | ||
239 | } | ||
266 | 240 | ||
267 | /** | 241 | /** |
268 | * Task run on errors. Reports an error and cleans up everything. | 242 | * Task run on errors. Reports an error and cleans up everything. |
@@ -276,21 +250,22 @@ do_error (void *cls) | |||
276 | struct MHD_Response *resp; | 250 | struct MHD_Response *resp; |
277 | char *json_error; | 251 | char *json_error; |
278 | 252 | ||
279 | GNUNET_asprintf (&json_error, | 253 | if (NULL == handle->emsg) |
280 | "{Error while processing request: %s}", | 254 | handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_UNKNOWN); |
281 | &handle->emsg); | 255 | |
256 | GNUNET_asprintf (&json_error, "{\"error\": \"%s\"}", handle->emsg); | ||
257 | |||
258 | if (0 == handle->response_code) | ||
259 | handle->response_code = MHD_HTTP_OK; | ||
282 | 260 | ||
283 | resp = GNUNET_REST_create_response (json_error); | 261 | resp = GNUNET_REST_create_response (json_error); |
284 | handle->proc (handle->proc_cls, | 262 | handle->proc (handle->proc_cls, resp, handle->response_code); |
285 | resp, | ||
286 | handle->response_code); | ||
287 | cleanup_handle (handle); | 263 | cleanup_handle (handle); |
288 | GNUNET_free (json_error); | 264 | GNUNET_free(json_error); |
289 | } | 265 | } |
290 | 266 | ||
291 | |||
292 | /** | 267 | /** |
293 | * Callback for IDENTITY_get() | 268 | * Callback for GET Request with subsystem |
294 | * | 269 | * |
295 | * @param cls the RequestHandle | 270 | * @param cls the RequestHandle |
296 | * @param ego the Ego found | 271 | * @param ego the Ego found |
@@ -298,157 +273,153 @@ do_error (void *cls) | |||
298 | * @param name the id of the ego | 273 | * @param name the id of the ego |
299 | */ | 274 | */ |
300 | static void | 275 | static void |
301 | get_ego_for_subsys (void *cls, | 276 | ego_get_for_subsystem (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx, |
302 | struct GNUNET_IDENTITY_Ego *ego, | 277 | const char *name) |
303 | void **ctx, | ||
304 | const char *name) | ||
305 | { | 278 | { |
306 | struct RequestHandle *handle = cls; | 279 | struct RequestHandle *handle = cls; |
307 | struct GNUNET_JSONAPI_Document *json_document; | ||
308 | struct GNUNET_JSONAPI_Resource *json_resource; | ||
309 | struct EgoEntry *ego_entry; | ||
310 | struct MHD_Response *resp; | 280 | struct MHD_Response *resp; |
311 | json_t *name_json; | 281 | struct GNUNET_CRYPTO_EcdsaPublicKey public_key; |
282 | json_t *json_root; | ||
312 | char *result_str; | 283 | char *result_str; |
284 | char *public_key_string; | ||
313 | 285 | ||
314 | json_document = GNUNET_JSONAPI_document_new (); | 286 | if(NULL == ego) |
315 | |||
316 | for (ego_entry = handle->ego_head; | ||
317 | NULL != ego_entry; | ||
318 | ego_entry = ego_entry->next) | ||
319 | { | ||
320 | if ( (NULL != name) && (0 != strcmp (name, ego_entry->identifier)) ) | ||
321 | continue; | ||
322 | if (NULL == name) | ||
323 | continue; | ||
324 | json_resource = GNUNET_JSONAPI_resource_new | ||
325 | (GNUNET_REST_JSONAPI_IDENTITY_EGO, ego_entry->keystring); | ||
326 | name_json = json_string (ego_entry->identifier); | ||
327 | GNUNET_JSONAPI_resource_add_attr (json_resource, | ||
328 | GNUNET_REST_JSONAPI_IDENTITY_NAME, | ||
329 | name_json); | ||
330 | json_decref (name_json); | ||
331 | GNUNET_JSONAPI_document_resource_add (json_document, json_resource); | ||
332 | break; | ||
333 | } | ||
334 | if (0 == GNUNET_JSONAPI_document_resource_count (json_document)) | ||
335 | { | 287 | { |
336 | GNUNET_JSONAPI_document_delete (json_document); | 288 | handle->emsg = GNUNET_strdup("No identity found for subsystem"); |
337 | handle->emsg = GNUNET_strdup("No identity matches results!"); | ||
338 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 289 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
339 | return; | 290 | return; |
340 | } | 291 | } |
341 | GNUNET_JSONAPI_document_serialize (json_document, &result_str); | 292 | |
342 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); | 293 | GNUNET_IDENTITY_ego_get_public_key(ego,&public_key); |
294 | public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string(&public_key); | ||
295 | |||
296 | // create json with subsystem identity | ||
297 | json_root = json_object (); | ||
298 | json_object_set_new (json_root, GNUNET_REST_PARAM_PUBKEY, json_string(public_key_string)); | ||
299 | json_object_set_new (json_root, GNUNET_REST_PARAM_NAME, json_string(name)); | ||
300 | |||
301 | result_str = json_dumps (json_root, 0); | ||
302 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); | ||
343 | resp = GNUNET_REST_create_response (result_str); | 303 | resp = GNUNET_REST_create_response (result_str); |
344 | GNUNET_JSONAPI_document_delete (json_document); | 304 | |
305 | json_decref (json_root); | ||
345 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); | 306 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); |
346 | GNUNET_free (result_str); | 307 | GNUNET_free(result_str); |
308 | GNUNET_free(public_key_string); | ||
347 | cleanup_handle (handle); | 309 | cleanup_handle (handle); |
348 | } | 310 | } |
349 | 311 | ||
350 | /** | 312 | /** |
351 | * Create a response with requested ego(s) | 313 | * Handle identity GET request |
352 | * | 314 | * |
353 | * @param con the Rest handle | 315 | * @param con_handle the connection handle |
354 | * @param url the requested url | 316 | * @param url the url |
355 | * @param cls the request handle | 317 | * @param cls the RequestHandle |
356 | */ | 318 | */ |
357 | static void | 319 | void |
358 | ego_info_response (struct GNUNET_REST_RequestHandle *con, | 320 | ego_get (struct GNUNET_REST_RequestHandle *con_handle, const char* url, |
359 | const char *url, | 321 | void *cls) |
360 | void *cls) | ||
361 | { | 322 | { |
362 | const char *egoname; | ||
363 | char *result_str; | ||
364 | char *subsys_val; | ||
365 | char *keystring; | ||
366 | struct RequestHandle *handle = cls; | 323 | struct RequestHandle *handle = cls; |
367 | struct EgoEntry *ego_entry; | 324 | struct EgoEntry *ego_entry; |
368 | struct GNUNET_HashCode key; | 325 | struct GNUNET_HashCode key; |
369 | struct MHD_Response *resp; | 326 | struct MHD_Response *resp; |
370 | struct GNUNET_JSONAPI_Document *json_document; | 327 | char *keystring; |
371 | struct GNUNET_JSONAPI_Resource *json_resource; | 328 | const char *egoname; |
372 | json_t *name_str; | 329 | json_t *json_root; |
373 | 330 | json_t *json_ego; | |
374 | if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url, GNUNET_REST_API_NS_IDENTITY)) | 331 | char *result_str; |
332 | size_t index; | ||
333 | |||
334 | //if subsystem | ||
335 | GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_SUBSYSTEM, | ||
336 | strlen (GNUNET_REST_PARAM_SUBSYSTEM), &key); | ||
337 | if ( GNUNET_YES | ||
338 | == GNUNET_CONTAINER_multihashmap_contains ( | ||
339 | handle->rest_handle->url_param_map, &key)) | ||
375 | { | 340 | { |
376 | resp = GNUNET_REST_create_response (NULL); | 341 | handle->subsystem = GNUNET_strdup( |
377 | handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST); | 342 | GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, |
378 | cleanup_handle (handle); | 343 | &key)); |
344 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", | ||
345 | handle->subsystem); | ||
346 | |||
347 | handle->op = GNUNET_IDENTITY_get (handle->identity_handle, | ||
348 | handle->subsystem, &ego_get_for_subsystem, | ||
349 | handle); | ||
350 | if (NULL == handle->op) | ||
351 | { | ||
352 | handle->emsg = GNUNET_strdup("No identity found for subsystem"); | ||
353 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
354 | return; | ||
355 | } | ||
379 | return; | 356 | return; |
380 | } | 357 | } |
381 | egoname = NULL; | 358 | egoname = NULL; |
382 | keystring = NULL; | 359 | keystring = NULL; |
383 | if (strlen (GNUNET_REST_API_NS_IDENTITY) < strlen (handle->url)) | 360 | |
361 | //if only one identity requested | ||
362 | GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_PUBKEY, | ||
363 | strlen (GNUNET_REST_PARAM_PUBKEY), &key); | ||
364 | if ( GNUNET_YES | ||
365 | == GNUNET_CONTAINER_multihashmap_contains ( | ||
366 | handle->rest_handle->url_param_map, &key)) | ||
384 | { | 367 | { |
385 | keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY)+1]; | 368 | keystring = GNUNET_CONTAINER_multihashmap_get ( |
386 | //Return all egos | 369 | handle->rest_handle->url_param_map, &key); |
370 | |||
387 | for (ego_entry = handle->ego_head; | 371 | for (ego_entry = handle->ego_head; |
388 | NULL != ego_entry; | 372 | NULL != ego_entry; ego_entry = ego_entry->next) |
389 | ego_entry = ego_entry->next) | ||
390 | { | 373 | { |
391 | if ( (NULL != keystring) && (0 != strcmp (keystring, ego_entry->keystring)) ) | 374 | if ((NULL != keystring) |
392 | continue; | 375 | && (0 != strcmp (keystring, ego_entry->keystring))) |
376 | continue; | ||
393 | egoname = ego_entry->identifier; | 377 | egoname = ego_entry->identifier; |
394 | } | 378 | } |
395 | } | 379 | } |
396 | 380 | ||
397 | if ( NULL == egoname ) { | 381 | json_root = json_array (); |
398 | GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM, | 382 | //Return ego/egos |
399 | strlen (GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM), | 383 | for (ego_entry = handle->ego_head; |
400 | &key); | 384 | NULL != ego_entry; ego_entry = ego_entry->next) |
401 | if ( GNUNET_YES == | 385 | { |
402 | GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map, | 386 | //if only one ego requested |
403 | &key) ) | 387 | if ((NULL != egoname)){ |
404 | { | 388 | if(0 != strcmp (egoname, ego_entry->identifier)){ |
405 | subsys_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map, | 389 | continue; |
406 | &key); | ||
407 | if (NULL != subsys_val) | ||
408 | { | ||
409 | GNUNET_asprintf (&handle->subsys, "%s", subsys_val); | ||
410 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsys_val); | ||
411 | handle->op = GNUNET_IDENTITY_get (handle->identity_handle, | ||
412 | handle->subsys, | ||
413 | &get_ego_for_subsys, | ||
414 | handle); | ||
415 | return; | ||
416 | } | 390 | } |
417 | } | 391 | } |
418 | } | ||
419 | 392 | ||
420 | json_document = GNUNET_JSONAPI_document_new (); | 393 | json_ego = json_object (); |
394 | json_object_set_new (json_ego, | ||
395 | GNUNET_REST_PARAM_PUBKEY, | ||
396 | json_string (ego_entry->keystring)); | ||
397 | json_object_set_new (json_ego, | ||
398 | GNUNET_REST_PARAM_NAME, | ||
399 | json_string (ego_entry->identifier)); | ||
400 | json_array_append (json_root, json_ego); | ||
401 | } | ||
421 | 402 | ||
422 | //Return all egos | 403 | if ((size_t) 0 == json_array_size (json_root)) |
423 | for (ego_entry = handle->ego_head; | ||
424 | NULL != ego_entry; | ||
425 | ego_entry = ego_entry->next) | ||
426 | { | 404 | { |
427 | if ( (NULL != egoname) && (0 != strcmp (egoname, ego_entry->identifier)) ) | 405 | json_decref (json_root); |
428 | continue; | 406 | handle->emsg = GNUNET_strdup("No identities found!"); |
429 | json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_EGO, | ||
430 | ego_entry->keystring); | ||
431 | name_str = json_string (ego_entry->identifier); | ||
432 | GNUNET_JSONAPI_resource_add_attr ( | ||
433 | json_resource, | ||
434 | GNUNET_REST_JSONAPI_IDENTITY_NAME, | ||
435 | name_str); | ||
436 | json_decref (name_str); | ||
437 | GNUNET_JSONAPI_document_resource_add (json_document, json_resource); | ||
438 | } | ||
439 | if (0 == GNUNET_JSONAPI_document_resource_count (json_document)) | ||
440 | { | ||
441 | GNUNET_JSONAPI_document_delete (json_document); | ||
442 | handle->emsg = GNUNET_strdup ("No identities found!"); | ||
443 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 407 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
444 | return; | 408 | return; |
445 | } | 409 | } |
446 | GNUNET_JSONAPI_document_serialize (json_document, &result_str); | 410 | |
447 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); | 411 | result_str = json_dumps (json_root, 0); |
412 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); | ||
448 | resp = GNUNET_REST_create_response (result_str); | 413 | resp = GNUNET_REST_create_response (result_str); |
449 | GNUNET_JSONAPI_document_delete (json_document); | 414 | |
415 | //delete json_objects in json_array with macro | ||
416 | json_array_foreach(json_root, index, json_ego ) | ||
417 | { | ||
418 | json_decref (json_ego); | ||
419 | } | ||
420 | json_decref (json_root); | ||
450 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); | 421 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); |
451 | GNUNET_free (result_str); | 422 | GNUNET_free(result_str); |
452 | cleanup_handle (handle); | 423 | cleanup_handle (handle); |
453 | } | 424 | } |
454 | 425 | ||
@@ -467,290 +438,290 @@ do_finished (void *cls, const char *emsg) | |||
467 | handle->op = NULL; | 438 | handle->op = NULL; |
468 | if (NULL != emsg) | 439 | if (NULL != emsg) |
469 | { | 440 | { |
470 | handle->emsg = GNUNET_strdup (emsg); | 441 | handle->emsg = GNUNET_strdup(emsg); |
471 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 442 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
472 | return; | 443 | return; |
473 | } | 444 | } |
474 | resp = GNUNET_REST_create_response (NULL); | 445 | resp = GNUNET_REST_create_response (NULL); |
475 | handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT); | 446 | handle->proc (handle->proc_cls, resp, handle->response_code); |
476 | cleanup_handle (handle); | 447 | cleanup_handle (handle); |
477 | } | 448 | } |
478 | 449 | ||
479 | /** | 450 | /** |
480 | * Create a new ego | 451 | * Handle identity PUT request |
481 | * | 452 | * |
482 | * @param con rest handle | 453 | * @param con_handle the connection handle |
483 | * @param url url | 454 | * @param url the url |
484 | * @param cls request handle | 455 | * @param cls the RequestHandle |
485 | */ | 456 | */ |
486 | static void | 457 | void |
487 | ego_create_cont (struct GNUNET_REST_RequestHandle *con, | 458 | ego_edit (struct GNUNET_REST_RequestHandle *con_handle, const char* url, |
488 | const char *url, | 459 | void *cls) |
489 | void *cls) | ||
490 | { | 460 | { |
491 | struct RequestHandle *handle = cls; | 461 | struct RequestHandle *handle = cls; |
492 | struct EgoEntry *ego_entry; | 462 | struct EgoEntry *ego_entry; |
463 | struct EgoEntry *ego_entry_tmp; | ||
493 | struct MHD_Response *resp; | 464 | struct MHD_Response *resp; |
494 | struct GNUNET_JSONAPI_Document *json_obj; | 465 | json_t *subsys_json; |
495 | struct GNUNET_JSONAPI_Resource *json_res; | 466 | json_t *name_json; |
496 | json_t *egoname_json; | 467 | json_t *key_json; |
497 | json_t *data_js; | 468 | json_t *data_js; |
498 | json_error_t err; | 469 | json_error_t err; |
499 | const char* egoname; | 470 | const char *keystring; |
500 | char term_data[handle->data_size+1]; | 471 | const char *subsys; |
501 | struct GNUNET_JSON_Specification docspec[] = { | 472 | const char *newname; |
502 | GNUNET_JSON_spec_jsonapi_document (&json_obj), | 473 | char term_data[handle->data_size + 1]; |
503 | GNUNET_JSON_spec_end() | 474 | int ego_exists = GNUNET_NO; |
504 | }; | 475 | |
505 | if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url)) | 476 | //if no data |
477 | if (0 >= handle->data_size) | ||
506 | { | 478 | { |
507 | handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID); | 479 | handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); |
508 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 480 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
509 | return; | 481 | return; |
510 | } | 482 | } |
511 | if (0 >= handle->data_size) | 483 | //if not json |
484 | term_data[handle->data_size] = '\0'; | ||
485 | GNUNET_memcpy(term_data, handle->data, handle->data_size); | ||
486 | data_js = json_loads (term_data,JSON_DECODE_ANY,&err); | ||
487 | if (NULL == data_js) | ||
512 | { | 488 | { |
513 | handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA); | 489 | handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); |
514 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 490 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
515 | return; | 491 | return; |
516 | } | 492 | } |
517 | term_data[handle->data_size] = '\0'; | 493 | if (!json_is_object(data_js)) |
518 | GNUNET_memcpy (term_data, handle->data, handle->data_size); | ||
519 | data_js = json_loads (term_data, | ||
520 | JSON_DECODE_ANY, | ||
521 | &err); | ||
522 | GNUNET_assert (NULL != data_js); | ||
523 | GNUNET_assert (GNUNET_OK == | ||
524 | GNUNET_JSON_parse (data_js, docspec, | ||
525 | NULL, NULL)); | ||
526 | |||
527 | json_decref (data_js); | ||
528 | |||
529 | if (NULL == json_obj) | ||
530 | { | 494 | { |
495 | json_decref (data_js); | ||
496 | handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); | ||
531 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 497 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
532 | return; | 498 | return; |
533 | } | 499 | } |
534 | if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) | 500 | //json must contain pubkey and (subsystem or name) |
501 | if (2 != json_object_size (data_js)) | ||
535 | { | 502 | { |
536 | GNUNET_JSONAPI_document_delete (json_obj); | 503 | json_decref (data_js); |
537 | handle->emsg = GNUNET_strdup ("Provided resource count invalid"); | 504 | handle->emsg = GNUNET_strdup("Resource amount invalid"); |
538 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 505 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
539 | return; | 506 | return; |
540 | } | 507 | } |
541 | json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); | 508 | |
542 | if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO)) | 509 | key_json = json_object_get (data_js, GNUNET_REST_PARAM_PUBKEY); |
510 | if ((NULL == key_json) || !json_is_string(key_json)) | ||
511 | { | ||
512 | json_decref (data_js); | ||
513 | handle->emsg = GNUNET_strdup("Missing element pubkey"); | ||
514 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
515 | return; | ||
516 | } | ||
517 | keystring = json_string_value (key_json); | ||
518 | |||
519 | for (ego_entry = handle->ego_head; | ||
520 | NULL != ego_entry; ego_entry = ego_entry->next) | ||
521 | { | ||
522 | if (0 != strcasecmp (keystring, ego_entry->keystring)) | ||
523 | continue; | ||
524 | ego_exists = GNUNET_YES; | ||
525 | break; | ||
526 | } | ||
527 | |||
528 | if (GNUNET_NO == ego_exists) | ||
543 | { | 529 | { |
544 | GNUNET_JSONAPI_document_delete (json_obj); | 530 | json_decref (data_js); |
545 | resp = GNUNET_REST_create_response (NULL); | 531 | resp = GNUNET_REST_create_response (NULL); |
546 | handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); | 532 | handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND); |
547 | cleanup_handle (handle); | 533 | cleanup_handle (handle); |
548 | return; | 534 | return; |
549 | } | 535 | } |
550 | egoname_json = GNUNET_JSONAPI_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_NAME); | 536 | //This is a rename |
551 | if (!json_is_string (egoname_json)) | 537 | name_json = json_object_get (data_js, GNUNET_REST_PARAM_NEWNAME); |
538 | if ((NULL != name_json) && json_is_string(name_json)) | ||
552 | { | 539 | { |
553 | GNUNET_JSONAPI_document_delete (json_obj); | 540 | newname = json_string_value (name_json); |
554 | handle->emsg = GNUNET_strdup ("No name provided"); | 541 | if (0 >= strlen (newname)) |
555 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 542 | { |
543 | json_decref (data_js); | ||
544 | handle->emsg = GNUNET_strdup("No name provided"); | ||
545 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
546 | return; | ||
547 | } | ||
548 | for (ego_entry_tmp = handle->ego_head; | ||
549 | NULL != ego_entry_tmp; ego_entry_tmp = ego_entry_tmp->next) | ||
550 | { | ||
551 | if (0 == strcasecmp (newname, ego_entry_tmp->identifier) | ||
552 | && 0 != strcasecmp (keystring, ego_entry_tmp->keystring)) | ||
553 | { | ||
554 | //Ego with same name not allowed | ||
555 | json_decref (data_js); | ||
556 | resp = GNUNET_REST_create_response (NULL); | ||
557 | handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); | ||
558 | cleanup_handle (handle); | ||
559 | return; | ||
560 | } | ||
561 | } | ||
562 | handle->response_code = MHD_HTTP_NO_CONTENT; | ||
563 | handle->op = GNUNET_IDENTITY_rename (handle->identity_handle, | ||
564 | ego_entry->identifier, newname, | ||
565 | &do_finished, handle); | ||
566 | json_decref (data_js); | ||
556 | return; | 567 | return; |
557 | } | 568 | } |
558 | egoname = json_string_value (egoname_json); | 569 | |
559 | for (ego_entry = handle->ego_head; | 570 | //Set subsystem |
560 | NULL != ego_entry; | 571 | subsys_json = json_object_get (data_js, GNUNET_REST_PARAM_SUBSYSTEM); |
561 | ego_entry = ego_entry->next) | 572 | if ((NULL != subsys_json) && json_is_string(subsys_json)) |
562 | { | 573 | { |
563 | if (0 == strcasecmp (egoname, ego_entry->identifier)) | 574 | subsys = json_string_value (subsys_json); |
575 | if (0 >= strlen (subsys)) | ||
564 | { | 576 | { |
565 | GNUNET_JSONAPI_document_delete (json_obj); | 577 | json_decref (data_js); |
566 | resp = GNUNET_REST_create_response (NULL); | 578 | handle->emsg = GNUNET_strdup("Invalid subsystem name"); |
567 | handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); | 579 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
568 | cleanup_handle (handle); | ||
569 | return; | 580 | return; |
570 | } | 581 | } |
582 | GNUNET_asprintf (&handle->subsystem, "%s", subsys); | ||
583 | json_decref (data_js); | ||
584 | handle->response_code = MHD_HTTP_NO_CONTENT; | ||
585 | handle->op = GNUNET_IDENTITY_set (handle->identity_handle, handle->subsystem, | ||
586 | ego_entry->ego, &do_finished, handle); | ||
587 | return; | ||
571 | } | 588 | } |
572 | GNUNET_asprintf (&handle->name, "%s", egoname); | 589 | json_decref (data_js); |
573 | GNUNET_JSONAPI_document_delete (json_obj); | 590 | handle->emsg = GNUNET_strdup("Subsystem not provided"); |
574 | handle->op = GNUNET_IDENTITY_create (handle->identity_handle, | 591 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
575 | handle->name, | ||
576 | &do_finished, | ||
577 | handle); | ||
578 | } | 592 | } |
579 | 593 | ||
580 | |||
581 | /** | 594 | /** |
582 | * Handle ego edit request | 595 | * Handle identity POST request |
583 | * | 596 | * |
584 | * @param con rest connection handle | 597 | * @param con_handle the connection handle |
585 | * @param url the url that is requested | 598 | * @param url the url |
586 | * @param cls the RequestHandle | 599 | * @param cls the RequestHandle |
587 | */ | 600 | */ |
588 | static void | 601 | void |
589 | ego_edit_cont (struct GNUNET_REST_RequestHandle *con, | 602 | ego_create (struct GNUNET_REST_RequestHandle *con_handle, const char* url, |
590 | const char *url, | 603 | void *cls) |
591 | void *cls) | ||
592 | { | 604 | { |
593 | struct GNUNET_JSONAPI_Document *json_obj; | ||
594 | struct GNUNET_JSONAPI_Resource *json_res; | ||
595 | struct RequestHandle *handle = cls; | 605 | struct RequestHandle *handle = cls; |
596 | struct EgoEntry *ego_entry; | 606 | struct EgoEntry *ego_entry; |
597 | struct EgoEntry *ego_entry_tmp; | ||
598 | struct MHD_Response *resp; | 607 | struct MHD_Response *resp; |
599 | json_t *subsys_json; | 608 | json_t *egoname_json; |
600 | json_t *name_json; | ||
601 | json_t *data_js; | 609 | json_t *data_js; |
602 | json_error_t err; | 610 | json_error_t err; |
603 | const char *keystring; | 611 | const char* egoname; |
604 | const char *subsys; | 612 | char term_data[handle->data_size + 1]; |
605 | const char *newname; | ||
606 | char term_data[handle->data_size+1]; | ||
607 | int ego_exists = GNUNET_NO; | ||
608 | struct GNUNET_JSON_Specification docspec[] = { | ||
609 | GNUNET_JSON_spec_jsonapi_document (&json_obj), | ||
610 | GNUNET_JSON_spec_end() | ||
611 | }; | ||
612 | 613 | ||
613 | if (strlen (GNUNET_REST_API_NS_IDENTITY) > strlen (handle->url)) | 614 | if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url)) |
614 | { | 615 | { |
615 | handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID); | 616 | handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_RESOURCE_INVALID); |
616 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 617 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
617 | return; | 618 | return; |
618 | } | 619 | } |
619 | 620 | ||
620 | keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1]; | ||
621 | |||
622 | for (ego_entry = handle->ego_head; | ||
623 | NULL != ego_entry; | ||
624 | ego_entry = ego_entry->next) | ||
625 | { | ||
626 | if (0 != strcasecmp (keystring, ego_entry->keystring)) | ||
627 | continue; | ||
628 | ego_exists = GNUNET_YES; | ||
629 | break; | ||
630 | } | ||
631 | |||
632 | if (GNUNET_NO == ego_exists) | ||
633 | { | ||
634 | resp = GNUNET_REST_create_response (NULL); | ||
635 | handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND); | ||
636 | cleanup_handle (handle); | ||
637 | return; | ||
638 | } | ||
639 | |||
640 | if (0 >= handle->data_size) | 621 | if (0 >= handle->data_size) |
641 | { | 622 | { |
642 | handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA); | 623 | handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA); |
643 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 624 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
644 | return; | 625 | return; |
645 | } | 626 | } |
646 | |||
647 | term_data[handle->data_size] = '\0'; | 627 | term_data[handle->data_size] = '\0'; |
648 | GNUNET_memcpy (term_data, handle->data, handle->data_size); | 628 | GNUNET_memcpy(term_data, handle->data, handle->data_size); |
649 | data_js = json_loads (term_data, | 629 | data_js = json_loads (term_data, |
650 | JSON_DECODE_ANY, | 630 | JSON_DECODE_ANY, |
651 | &err); | 631 | &err); |
652 | GNUNET_assert (NULL != data_js); | ||
653 | GNUNET_assert (GNUNET_OK == | ||
654 | GNUNET_JSON_parse (data_js, docspec, | ||
655 | NULL, NULL)); | ||
656 | |||
657 | json_decref (data_js); | ||
658 | 632 | ||
659 | if (NULL == json_obj) | 633 | if (NULL == data_js) |
660 | { | 634 | { |
661 | handle->emsg = GNUNET_strdup ("Data invalid"); | 635 | handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); |
662 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 636 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
663 | return; | 637 | return; |
664 | } | 638 | } |
665 | 639 | //instead of parse | |
666 | if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) | 640 | if (!json_is_object(data_js)) |
667 | { | 641 | { |
668 | GNUNET_JSONAPI_document_delete (json_obj); | 642 | json_decref (data_js); |
669 | handle->emsg = GNUNET_strdup ("Resource amount invalid"); | 643 | handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID); |
670 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 644 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
671 | return; | 645 | return; |
672 | } | 646 | } |
673 | json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); | ||
674 | 647 | ||
675 | if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO)) | 648 | if (1 != json_object_size (data_js)) |
676 | { | 649 | { |
677 | GNUNET_JSONAPI_document_delete (json_obj); | 650 | json_decref (data_js); |
678 | handle->emsg = GNUNET_strdup ("Resource type invalid"); | 651 | handle->emsg = GNUNET_strdup("Provided resource count invalid"); |
679 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 652 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
680 | return; | 653 | return; |
681 | } | 654 | } |
682 | 655 | ||
683 | //This is a rename | 656 | egoname_json = json_object_get (data_js, GNUNET_REST_PARAM_NAME); |
684 | name_json = GNUNET_JSONAPI_resource_read_attr (json_res, | 657 | if (!json_is_string(egoname_json)) |
685 | GNUNET_REST_JSONAPI_IDENTITY_NEWNAME); | ||
686 | if ((NULL != name_json) && json_is_string (name_json)) | ||
687 | { | 658 | { |
688 | newname = json_string_value (name_json); | 659 | json_decref (data_js); |
689 | for (ego_entry_tmp = handle->ego_head; | 660 | handle->emsg = GNUNET_strdup("No name provided"); |
690 | NULL != ego_entry_tmp; | 661 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
691 | ego_entry_tmp = ego_entry_tmp->next) | ||
692 | { | ||
693 | if (0 == strcasecmp (newname, ego_entry_tmp->identifier) && | ||
694 | 0 != strcasecmp (keystring, ego_entry_tmp->keystring)) | ||
695 | { | ||
696 | //Ego with same name not allowed | ||
697 | GNUNET_JSONAPI_document_delete (json_obj); | ||
698 | resp = GNUNET_REST_create_response (NULL); | ||
699 | handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); | ||
700 | cleanup_handle (handle); | ||
701 | return; | ||
702 | } | ||
703 | } | ||
704 | handle->op = GNUNET_IDENTITY_rename (handle->identity_handle, | ||
705 | ego_entry->identifier, | ||
706 | newname, | ||
707 | &do_finished, | ||
708 | handle); | ||
709 | GNUNET_JSONAPI_document_delete (json_obj); | ||
710 | return; | 662 | return; |
711 | } | 663 | } |
712 | 664 | egoname = json_string_value (egoname_json); | |
713 | //Set subsystem | 665 | if (0 >= strlen (egoname)) |
714 | subsys_json = GNUNET_JSONAPI_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM); | ||
715 | if ( (NULL != subsys_json) && json_is_string (subsys_json)) | ||
716 | { | 666 | { |
717 | subsys = json_string_value (subsys_json); | 667 | json_decref (data_js); |
718 | GNUNET_asprintf (&handle->subsys, "%s", subsys); | 668 | handle->emsg = GNUNET_strdup("No name provided"); |
719 | GNUNET_JSONAPI_document_delete (json_obj); | 669 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
720 | handle->op = GNUNET_IDENTITY_set (handle->identity_handle, | ||
721 | handle->subsys, | ||
722 | ego_entry->ego, | ||
723 | &do_finished, | ||
724 | handle); | ||
725 | return; | 670 | return; |
726 | } | 671 | } |
727 | GNUNET_JSONAPI_document_delete (json_obj); | 672 | for (ego_entry = handle->ego_head; |
728 | handle->emsg = GNUNET_strdup ("Subsystem not provided"); | 673 | NULL != ego_entry; ego_entry = ego_entry->next) |
729 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 674 | { |
675 | if (0 == strcasecmp (egoname, ego_entry->identifier)) | ||
676 | { | ||
677 | json_decref (data_js); | ||
678 | resp = GNUNET_REST_create_response (NULL); | ||
679 | handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); | ||
680 | cleanup_handle (handle); | ||
681 | return; | ||
682 | } | ||
683 | } | ||
684 | GNUNET_asprintf (&handle->name, "%s", egoname); | ||
685 | json_decref (data_js); | ||
686 | handle->response_code = MHD_HTTP_CREATED; | ||
687 | handle->op = GNUNET_IDENTITY_create (handle->identity_handle, handle->name, | ||
688 | &do_finished, handle); | ||
730 | } | 689 | } |
731 | 690 | ||
691 | /** | ||
692 | * Handle identity DELETE request | ||
693 | * | ||
694 | * @param con_handle the connection handle | ||
695 | * @param url the url | ||
696 | * @param cls the RequestHandle | ||
697 | */ | ||
732 | void | 698 | void |
733 | ego_delete_cont (struct GNUNET_REST_RequestHandle *con_handle, | 699 | ego_delete (struct GNUNET_REST_RequestHandle *con_handle, const char* url, |
734 | const char* url, | 700 | void *cls) |
735 | void *cls) | ||
736 | { | 701 | { |
737 | const char *keystring; | 702 | const char *keystring; |
738 | struct EgoEntry *ego_entry; | 703 | struct EgoEntry *ego_entry; |
704 | struct GNUNET_HashCode key; | ||
739 | struct MHD_Response *resp; | 705 | struct MHD_Response *resp; |
740 | struct RequestHandle *handle = cls; | 706 | struct RequestHandle *handle = cls; |
741 | int ego_exists = GNUNET_NO; | 707 | int ego_exists = GNUNET_NO; |
742 | 708 | ||
743 | if (strlen (GNUNET_REST_API_NS_IDENTITY) >= strlen (handle->url)) | 709 | //if only one identity requested |
710 | GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_PUBKEY, | ||
711 | strlen (GNUNET_REST_PARAM_PUBKEY), &key); | ||
712 | if ( GNUNET_NO | ||
713 | == GNUNET_CONTAINER_multihashmap_contains ( | ||
714 | handle->rest_handle->url_param_map, &key)) | ||
744 | { | 715 | { |
745 | handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID); | 716 | handle->emsg = GNUNET_strdup("Missing parameter pubkey"); |
746 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 717 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
747 | return; | 718 | return; |
748 | } | 719 | } |
749 | 720 | ||
750 | keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1]; | 721 | keystring = GNUNET_CONTAINER_multihashmap_get ( |
722 | handle->rest_handle->url_param_map,&key); | ||
751 | for (ego_entry = handle->ego_head; | 723 | for (ego_entry = handle->ego_head; |
752 | NULL != ego_entry; | 724 | NULL != ego_entry; ego_entry = ego_entry->next) |
753 | ego_entry = ego_entry->next) | ||
754 | { | 725 | { |
755 | if (0 != strcasecmp (keystring, ego_entry->keystring)) | 726 | if (0 != strcasecmp (keystring, ego_entry->keystring)) |
756 | continue; | 727 | continue; |
@@ -764,14 +735,13 @@ ego_delete_cont (struct GNUNET_REST_RequestHandle *con_handle, | |||
764 | cleanup_handle (handle); | 735 | cleanup_handle (handle); |
765 | return; | 736 | return; |
766 | } | 737 | } |
738 | handle->response_code = MHD_HTTP_NO_CONTENT; | ||
767 | handle->op = GNUNET_IDENTITY_delete (handle->identity_handle, | 739 | handle->op = GNUNET_IDENTITY_delete (handle->identity_handle, |
768 | ego_entry->identifier, | 740 | ego_entry->identifier, &do_finished, |
769 | &do_finished, | 741 | handle); |
770 | handle); | ||
771 | 742 | ||
772 | } | 743 | } |
773 | 744 | ||
774 | |||
775 | /** | 745 | /** |
776 | * Respond to OPTIONS request | 746 | * Respond to OPTIONS request |
777 | * | 747 | * |
@@ -780,18 +750,15 @@ ego_delete_cont (struct GNUNET_REST_RequestHandle *con_handle, | |||
780 | * @param cls the RequestHandle | 750 | * @param cls the RequestHandle |
781 | */ | 751 | */ |
782 | static void | 752 | static void |
783 | options_cont (struct GNUNET_REST_RequestHandle *con_handle, | 753 | options_cont (struct GNUNET_REST_RequestHandle *con_handle, const char* url, |
784 | const char* url, | 754 | void *cls) |
785 | void *cls) | ||
786 | { | 755 | { |
787 | struct MHD_Response *resp; | 756 | struct MHD_Response *resp; |
788 | struct RequestHandle *handle = cls; | 757 | struct RequestHandle *handle = cls; |
789 | 758 | ||
790 | //For now, independent of path return all options | 759 | //For now, independent of path return all options |
791 | resp = GNUNET_REST_create_response (NULL); | 760 | resp = GNUNET_REST_create_response (NULL); |
792 | MHD_add_response_header (resp, | 761 | MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods); |
793 | "Access-Control-Allow-Methods", | ||
794 | allow_methods); | ||
795 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); | 762 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); |
796 | cleanup_handle (handle); | 763 | cleanup_handle (handle); |
797 | return; | 764 | return; |
@@ -807,18 +774,17 @@ init_cont (struct RequestHandle *handle) | |||
807 | { | 774 | { |
808 | struct GNUNET_REST_RequestHandlerError err; | 775 | struct GNUNET_REST_RequestHandlerError err; |
809 | static const struct GNUNET_REST_RequestHandler handlers[] = { | 776 | static const struct GNUNET_REST_RequestHandler handlers[] = { |
810 | {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_info_response}, | 777 | { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_get }, |
811 | {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create_cont}, | 778 | { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY, &ego_edit }, |
812 | {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY, &ego_edit_cont}, | 779 | { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create }, |
813 | {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY, &ego_delete_cont}, | 780 | { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY, &ego_delete }, |
814 | {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont}, | 781 | { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont }, |
815 | GNUNET_REST_HANDLER_END | 782 | GNUNET_REST_HANDLER_END |
816 | }; | 783 | }; |
817 | 784 | ||
818 | if (GNUNET_NO == GNUNET_JSONAPI_handle_request (handle->conndata_handle, | 785 | if (GNUNET_NO |
819 | handlers, | 786 | == GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, |
820 | &err, | 787 | handle)) |
821 | handle)) | ||
822 | { | 788 | { |
823 | handle->response_code = err.error_code; | 789 | handle->response_code = err.error_code; |
824 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 790 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
@@ -859,10 +825,8 @@ init_cont (struct RequestHandle *handle) | |||
859 | * must thus no longer be used | 825 | * must thus no longer be used |
860 | */ | 826 | */ |
861 | static void | 827 | static void |
862 | list_ego (void *cls, | 828 | init_egos (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx, |
863 | struct GNUNET_IDENTITY_Ego *ego, | 829 | const char *identifier) |
864 | void **ctx, | ||
865 | const char *identifier) | ||
866 | { | 830 | { |
867 | struct RequestHandle *handle = cls; | 831 | struct RequestHandle *handle = cls; |
868 | struct EgoEntry *ego_entry; | 832 | struct EgoEntry *ego_entry; |
@@ -874,16 +838,16 @@ list_ego (void *cls, | |||
874 | init_cont (handle); | 838 | init_cont (handle); |
875 | return; | 839 | return; |
876 | } | 840 | } |
877 | if (ID_REST_STATE_INIT == handle->state) { | 841 | if (ID_REST_STATE_INIT == handle->state) |
878 | ego_entry = GNUNET_new (struct EgoEntry); | 842 | { |
843 | ego_entry = GNUNET_new(struct EgoEntry); | ||
879 | GNUNET_IDENTITY_ego_get_public_key (ego, &pk); | 844 | GNUNET_IDENTITY_ego_get_public_key (ego, &pk); |
880 | ego_entry->keystring = | 845 | ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); |
881 | GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); | ||
882 | ego_entry->ego = ego; | 846 | ego_entry->ego = ego; |
883 | GNUNET_asprintf (&ego_entry->identifier, "%s", identifier); | 847 | GNUNET_asprintf (&ego_entry->identifier, "%s", identifier); |
884 | GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); | 848 | GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail, |
849 | ego_entry); | ||
885 | } | 850 | } |
886 | |||
887 | } | 851 | } |
888 | 852 | ||
889 | /** | 853 | /** |
@@ -898,39 +862,30 @@ list_ego (void *cls, | |||
898 | * @return GNUNET_OK if request accepted | 862 | * @return GNUNET_OK if request accepted |
899 | */ | 863 | */ |
900 | static void | 864 | static void |
901 | rest_identity_process_request(struct GNUNET_REST_RequestHandle *conndata_handle, | 865 | rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle, |
902 | GNUNET_REST_ResultProcessor proc, | 866 | GNUNET_REST_ResultProcessor proc, void *proc_cls) |
903 | void *proc_cls) | ||
904 | { | 867 | { |
905 | struct RequestHandle *handle = GNUNET_new (struct RequestHandle); | 868 | struct RequestHandle *handle = GNUNET_new(struct RequestHandle); |
906 | |||
907 | |||
908 | 869 | ||
870 | handle->response_code = 0; | ||
909 | handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; | 871 | handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; |
910 | |||
911 | handle->proc_cls = proc_cls; | 872 | handle->proc_cls = proc_cls; |
912 | handle->proc = proc; | 873 | handle->proc = proc; |
913 | handle->state = ID_REST_STATE_INIT; | 874 | handle->rest_handle = rest_handle; |
914 | handle->conndata_handle = conndata_handle; | 875 | handle->data = rest_handle->data; |
915 | handle->data = conndata_handle->data; | 876 | handle->data_size = rest_handle->data_size; |
916 | handle->data_size = conndata_handle->data_size; | 877 | |
917 | handle->method = conndata_handle->method; | 878 | handle->url = GNUNET_strdup(rest_handle->url); |
918 | GNUNET_asprintf (&handle->url, "%s", conndata_handle->url); | 879 | if (handle->url[strlen (handle->url) - 1] == '/') |
919 | if (handle->url[strlen (handle->url)-1] == '/') | 880 | handle->url[strlen (handle->url) - 1] = '\0'; |
920 | handle->url[strlen (handle->url)-1] = '\0'; | 881 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); |
921 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 882 | |
922 | "Connecting...\n"); | 883 | handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &init_egos, handle); |
923 | handle->identity_handle = GNUNET_IDENTITY_connect (cfg, | 884 | |
924 | &list_ego, | 885 | handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout, |
925 | handle); | 886 | &do_error, handle); |
926 | handle->timeout_task = | 887 | |
927 | GNUNET_SCHEDULER_add_delayed (handle->timeout, | 888 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); |
928 | &do_error, | ||
929 | handle); | ||
930 | |||
931 | |||
932 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
933 | "Connected\n"); | ||
934 | } | 889 | } |
935 | 890 | ||
936 | /** | 891 | /** |
@@ -947,27 +902,24 @@ libgnunet_plugin_rest_identity_init (void *cls) | |||
947 | 902 | ||
948 | cfg = cls; | 903 | cfg = cls; |
949 | if (NULL != plugin.cfg) | 904 | if (NULL != plugin.cfg) |
950 | return NULL; /* can only initialize once! */ | 905 | return NULL; /* can only initialize once! */ |
951 | memset (&plugin, 0, sizeof (struct Plugin)); | 906 | memset (&plugin, 0, sizeof(struct Plugin)); |
952 | plugin.cfg = cfg; | 907 | plugin.cfg = cfg; |
953 | api = GNUNET_new (struct GNUNET_REST_Plugin); | 908 | api = GNUNET_new(struct GNUNET_REST_Plugin); |
954 | api->cls = &plugin; | 909 | api->cls = &plugin; |
955 | api->name = GNUNET_REST_API_NS_IDENTITY; | 910 | api->name = GNUNET_REST_API_NS_IDENTITY; |
956 | api->process_request = &rest_identity_process_request; | 911 | api->process_request = &rest_process_request; |
957 | GNUNET_asprintf (&allow_methods, | 912 | GNUNET_asprintf (&allow_methods, "%s, %s, %s, %s, %s", |
958 | "%s, %s, %s, %s, %s", | 913 | MHD_HTTP_METHOD_GET, |
959 | MHD_HTTP_METHOD_GET, | 914 | MHD_HTTP_METHOD_POST, |
960 | MHD_HTTP_METHOD_POST, | 915 | MHD_HTTP_METHOD_PUT, |
961 | MHD_HTTP_METHOD_PUT, | 916 | MHD_HTTP_METHOD_DELETE, |
962 | MHD_HTTP_METHOD_DELETE, | 917 | MHD_HTTP_METHOD_OPTIONS); |
963 | MHD_HTTP_METHOD_OPTIONS); | 918 | |
964 | 919 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Identity REST API initialized\n")); | |
965 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
966 | _("Identity REST API initialized\n")); | ||
967 | return api; | 920 | return api; |
968 | } | 921 | } |
969 | 922 | ||
970 | |||
971 | /** | 923 | /** |
972 | * Exit point from the plugin. | 924 | * Exit point from the plugin. |
973 | * | 925 | * |
@@ -979,13 +931,13 @@ libgnunet_plugin_rest_identity_done (void *cls) | |||
979 | { | 931 | { |
980 | struct GNUNET_REST_Plugin *api = cls; | 932 | struct GNUNET_REST_Plugin *api = cls; |
981 | struct Plugin *plugin = api->cls; | 933 | struct Plugin *plugin = api->cls; |
982 | |||
983 | plugin->cfg = NULL; | 934 | plugin->cfg = NULL; |
984 | GNUNET_free_non_null (allow_methods); | 935 | |
985 | GNUNET_free (api); | 936 | GNUNET_free_non_null(allow_methods); |
986 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 937 | GNUNET_free(api); |
987 | "Identity REST plugin is finished\n"); | 938 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n"); |
988 | return NULL; | 939 | return NULL; |
989 | } | 940 | } |
990 | 941 | ||
991 | /* end of plugin_rest_gns.c */ | 942 | /* end of plugin_rest_identity.c */ |
943 | |||
diff --git a/src/identity/test_plugin_identity_rest.sh b/src/identity/test_plugin_identity_rest.sh new file mode 100755 index 000000000..d43f4206b --- /dev/null +++ b/src/identity/test_plugin_identity_rest.sh | |||
@@ -0,0 +1,252 @@ | |||
1 | #!/usr/bin/bash | ||
2 | |||
3 | #First, start gnunet-arm and the rest-service. Make sure, no identity exists | ||
4 | |||
5 | link_to_api="http://localhost:7776/identity" | ||
6 | wrong_link="http://localhost:7776/idenmmmy" | ||
7 | |||
8 | #Test GET (multiple identities) for error when no identity exists | ||
9 | |||
10 | echo "No test for subsystem available" | ||
11 | echo "The next test case can be ignored if you have already added identities" | ||
12 | cache="$(curl --silent "$link_to_api" | grep "error")" | ||
13 | if [ "" == "$cache" ] | ||
14 | then | ||
15 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for GET request when missing identity\n" | ||
16 | else | ||
17 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for GET request when missing identity\n" | ||
18 | fi | ||
19 | |||
20 | #Test POST success code, error response code and error json | ||
21 | echo "The next test case can be ignored if you have already added an identity with the name Test" | ||
22 | cache="$(curl -v -X "POST" "$link_to_api" --data "{\"name\":\"Test\"}" 2>&1 | grep "HTTP/1.1 201")" | ||
23 | if [ "" == "$cache" ] | ||
24 | then | ||
25 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Error for good POST request\n" | ||
26 | else | ||
27 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Success for good POST request\n" | ||
28 | fi | ||
29 | |||
30 | cache="$(curl -v -X "POST" "$link_to_api" --data "{\"name\":\"Test\"}" 2>&1 | grep "HTTP/1.1 409")" | ||
31 | if [ "" == "$cache" ] | ||
32 | then | ||
33 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for duplicate name POST request\n" | ||
34 | else | ||
35 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for duplicate name POST request\n" | ||
36 | fi | ||
37 | |||
38 | cache="$(curl -v -X "POST" "$link_to_api" 2>&1 | grep "error")" | ||
39 | if [ "" == "$cache" ] | ||
40 | then | ||
41 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for no data POST request\n" | ||
42 | else | ||
43 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for no data POST request\n" | ||
44 | fi | ||
45 | |||
46 | cache="$(curl -v -X "POST" "$link_to_api" --data "wrong" 2>&1 | grep "error")" | ||
47 | if [ "" == "$cache" ] | ||
48 | then | ||
49 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for wrong data POST request\n" | ||
50 | else | ||
51 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for wrong data POST request\n" | ||
52 | fi | ||
53 | |||
54 | cache="$(curl -v -X "POST" "$link_to_api" --data "[{}]" 2>&1 | grep "error")" | ||
55 | if [ "" == "$cache" ] | ||
56 | then | ||
57 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for json array input POST request\n" | ||
58 | else | ||
59 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for json array input POST request\n" | ||
60 | fi | ||
61 | |||
62 | cache="$(curl -v -X "POST" "$link_to_api" --data "{\"name\":\"Test\",\"other\":\"Test\"}" 2>&1 | grep "error")" | ||
63 | if [ "" == "$cache" ] | ||
64 | then | ||
65 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for multi element json POST request\n" | ||
66 | else | ||
67 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for multi element json POST request\n" | ||
68 | fi | ||
69 | |||
70 | cache="$(curl -v -X "POST" "$link_to_api" --data "{\"nam\":\"Test\"}" 2>&1 | grep "error")" | ||
71 | if [ "" == "$cache" ] | ||
72 | then | ||
73 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for wrong json POST request\n" | ||
74 | else | ||
75 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for wrong json POST request\n" | ||
76 | fi | ||
77 | |||
78 | cache="$(curl -v -X "POST" "$link_to_api" --data "{\"name\":123}" 2>&1 | grep "error")" | ||
79 | if [ "" == "$cache" ] | ||
80 | then | ||
81 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for wrong json type POST request\n" | ||
82 | else | ||
83 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for wrong json type POST request\n" | ||
84 | fi | ||
85 | |||
86 | cache="$(curl -v -X "POST" "$link_to_api" --data "{\"name\":""}" 2>&1 | grep "error")" | ||
87 | if [ "" == "$cache" ] | ||
88 | then | ||
89 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for no name POST request\n" | ||
90 | else | ||
91 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for no name POST request\n" | ||
92 | fi | ||
93 | |||
94 | |||
95 | #Test GET (multiple identities) for success and error json | ||
96 | cache="$(curl --silent "$link_to_api" | grep "error")" | ||
97 | if [ "" == "$cache" ] | ||
98 | then | ||
99 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Success for good GET request (multiple identities)\n" | ||
100 | else | ||
101 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Error for good GET request (multiple identities)\n" | ||
102 | fi | ||
103 | |||
104 | |||
105 | id="$(gnunet-identity -d | grep "Test - " | sed "s/Test - //g")" | ||
106 | #Test GET (one identity) for success and error json | ||
107 | cache="$(curl --silent "${link_to_api}/$id" | grep "error")" | ||
108 | if [ "" == "$cache" ] | ||
109 | then | ||
110 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Success for good GET request (one identity)\n" | ||
111 | else | ||
112 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Error for good GET request (one identity)\n" | ||
113 | fi | ||
114 | |||
115 | |||
116 | #Test DELETE success code, error response code and error json | ||
117 | echo "Next tests for DELETE will probably fail when POST fails" | ||
118 | cache="$(curl -v -X "DELETE" "${link_to_api}/$id" 2>&1 | grep "HTTP/1.1 404")" | ||
119 | if [ "" == "$cache" ] | ||
120 | then | ||
121 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Success for good DELETE request\n" | ||
122 | else | ||
123 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Error for good DELETE request\n" | ||
124 | fi | ||
125 | |||
126 | curl --silent -X "POST" "$link_to_api" --data "{\"name\":\"Test\"}" | ||
127 | id="$(gnunet-identity -d | grep "Test - " | sed "s/Test - //g")" | ||
128 | |||
129 | cache="$(curl -v -X "DELETE" "${link_to_api}/df1" 2>&1 | grep "HTTP/1.1 404")" | ||
130 | if [ "" == "$cache" ] | ||
131 | then | ||
132 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for wrong DELETE request\n" | ||
133 | else | ||
134 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for wrong DELETE request\n" | ||
135 | fi | ||
136 | |||
137 | #Test PUT success code, error response codes and error json | ||
138 | cache="$(curl -v -X "PUT" "${link_to_api}/$id" --data "{\"newname\":\"NewTest\"}" 2>&1 | grep "HTTP/1.1 204")" | ||
139 | if [ "" == "$cache" ] | ||
140 | then | ||
141 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Error for good PUT request\n" | ||
142 | else | ||
143 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Success for good PUT request\n" | ||
144 | fi | ||
145 | |||
146 | cache="$(curl -v -X "PUT" "${link_to_api}/${id}1" --data "{\"newname\":\"NewNewTest\"}" 2>&1 | grep "HTTP/1.1 404")" | ||
147 | if [ "" == "$cache" ] | ||
148 | then | ||
149 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for wrong identity PUT request\n" | ||
150 | else | ||
151 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for wrong identity PUT request\n" | ||
152 | fi | ||
153 | |||
154 | cache="$(curl -v -X "PUT" "$link_to_api/$id" --data "{\"newname\":\"NewTest\"}" 2>&1 | grep "error")" | ||
155 | if [ "" == "$cache" ] | ||
156 | then | ||
157 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for duplicate name PUT request\n" | ||
158 | else | ||
159 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for duplicate name PUT request\n" | ||
160 | fi | ||
161 | |||
162 | cache="$(curl -v -X "PUT" "$link_to_api/$id" 2>&1 | grep "error")" | ||
163 | if [ "" == "$cache" ] | ||
164 | then | ||
165 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for no data PUT request\n" | ||
166 | else | ||
167 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for no data PUT request\n" | ||
168 | fi | ||
169 | |||
170 | cache="$(curl -v -X "PUT" "$link_to_api/$id" --data "wrong" 2>&1 | grep "error")" | ||
171 | if [ "" == "$cache" ] | ||
172 | then | ||
173 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for wrong data PUT request\n" | ||
174 | else | ||
175 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for wrong data PUT request\n" | ||
176 | fi | ||
177 | |||
178 | cache="$(curl -v -X "PUT" "$link_to_api/$id" --data "[{}]" 2>&1 | grep "error")" | ||
179 | if [ "" == "$cache" ] | ||
180 | then | ||
181 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for json array input PUT request\n" | ||
182 | else | ||
183 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for json array input PUT request\n" | ||
184 | fi | ||
185 | |||
186 | cache="$(curl -v -X "PUT" "$link_to_api/$id" --data "{\"newname\":\"Test\",\"other\":\"Test\"}" 2>&1 | grep "error")" | ||
187 | if [ "" == "$cache" ] | ||
188 | then | ||
189 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for multi element json PUT request\n" | ||
190 | else | ||
191 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for multi element json PUT request\n" | ||
192 | fi | ||
193 | |||
194 | cache="$(curl -v -X "PUT" "$link_to_api/$id" --data "{\"newnam\":\"Test\"}" 2>&1 | grep "error")" | ||
195 | if [ "" == "$cache" ] | ||
196 | then | ||
197 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for wrong json PUT request\n" | ||
198 | else | ||
199 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for wrong json PUT request\n" | ||
200 | fi | ||
201 | |||
202 | cache="$(curl -v -X "PUT" "$link_to_api/$id" --data "{\"newname\":123}" 2>&1 | grep "error")" | ||
203 | if [ "" == "$cache" ] | ||
204 | then | ||
205 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for wrong json type PUT request\n" | ||
206 | else | ||
207 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for wrong json type PUT request\n" | ||
208 | fi | ||
209 | |||
210 | cache="$(curl -v -X "PUT" "$link_to_api/$id" --data "{\"newname\":""}" 2>&1 | grep "error")" | ||
211 | if [ "" == "$cache" ] | ||
212 | then | ||
213 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for no name PUT request\n" | ||
214 | else | ||
215 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for no name PUT request\n" | ||
216 | fi | ||
217 | #TODO Missing subsystem test | ||
218 | |||
219 | #Missing OPTIONS success - nothing can really go wrong here | ||
220 | |||
221 | #Test wrong url | ||
222 | cache="$(curl -v "$wrong_link" 2>&1 | grep "HTTP/1.1 404")" | ||
223 | if [ "" == "$cache" ] | ||
224 | then | ||
225 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for wrong url GET request \n" | ||
226 | else | ||
227 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for wrong url GET request \n" | ||
228 | fi | ||
229 | |||
230 | cache="$(curl -X "PUT" -v "$wrong_link/$id" --data "{\"newname\":\"Testing\"}" 2>&1 | grep "HTTP/1.1 404")" | ||
231 | if [ "" == "$cache" ] | ||
232 | then | ||
233 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for wrong url GET request \n" | ||
234 | else | ||
235 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for wrong url GET request \n" | ||
236 | fi | ||
237 | |||
238 | cache="$(curl -X "POST" -v "$wrong_link/$id" --data "{\"name\":\"Test\"}" 2>&1 | grep "HTTP/1.1 404")" | ||
239 | if [ "" == "$cache" ] | ||
240 | then | ||
241 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for wrong url POST request \n" | ||
242 | else | ||
243 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for wrong url POST request \n" | ||
244 | fi | ||
245 | |||
246 | cache="$(curl -X "DELETE" -v "${wrong_link}/$id" 2>&1 | grep "HTTP/1.1 404")" | ||
247 | if [ "" == "$cache" ] | ||
248 | then | ||
249 | echo -n -e "[\033[0;31m FAILURE\033[0m ] Success for wrong url DELETE request \n" | ||
250 | else | ||
251 | echo -n -e "[\033[0;32m SUCCESS\033[0m ] Error for wrong url DELETE request \n" | ||
252 | fi | ||
diff --git a/src/identity/test_plugin_rest_identity.sh b/src/identity/test_plugin_rest_identity.sh new file mode 100755 index 000000000..b48becc45 --- /dev/null +++ b/src/identity/test_plugin_rest_identity.sh | |||
@@ -0,0 +1,216 @@ | |||
1 | #!/usr/bin/bash | ||
2 | |||
3 | #First, start gnunet-arm and the rest-service. Make sure, no identity exists | ||
4 | #Exit 0 means success, exit 1 means failed test | ||
5 | |||
6 | #No test for subsystem available | ||
7 | |||
8 | link_to_api="http://localhost:7776/identity" | ||
9 | wrong_link="http://localhost:7776/idenmmmy" | ||
10 | wrong_link2="http://localhost:7776/identityandmore" | ||
11 | |||
12 | #Test GET (multiple identities) for error when no identity exists | ||
13 | #The next test case can be ignored if you have already added identities | ||
14 | cache="$(curl --silent "$link_to_api" | grep "error")" | ||
15 | if [ "" == "$cache" ] | ||
16 | then | ||
17 | exit 1 | ||
18 | fi | ||
19 | |||
20 | #Test POST success code, error response code and error json | ||
21 | #The next test case can be ignored if you have already added an identity with the name Test | ||
22 | cache="$(curl -v -X "POST" "$link_to_api" --data "{\"name\":\"Test\"}" 2>&1 | grep "HTTP/1.1 201")" | ||
23 | if [ "" == "$cache" ] | ||
24 | then | ||
25 | exit 1 | ||
26 | fi | ||
27 | |||
28 | cache="$(curl -v -X "POST" "$link_to_api" --data "{\"name\":\"Test\"}" 2>&1 | grep "HTTP/1.1 409")" | ||
29 | if [ "" == "$cache" ] | ||
30 | then | ||
31 | exit 1 | ||
32 | fi | ||
33 | |||
34 | cache="$(curl -v -X "POST" "$link_to_api" 2>&1 | grep "error")" | ||
35 | if [ "" == "$cache" ] | ||
36 | then | ||
37 | exit 1 | ||
38 | fi | ||
39 | |||
40 | cache="$(curl -v -X "POST" "$link_to_api" --data "wrong" 2>&1 | grep "error")" | ||
41 | if [ "" == "$cache" ] | ||
42 | then | ||
43 | exit 1 | ||
44 | fi | ||
45 | |||
46 | cache="$(curl -v -X "POST" "$link_to_api" --data "[{}]" 2>&1 | grep "error")" | ||
47 | if [ "" == "$cache" ] | ||
48 | then | ||
49 | exit 1 | ||
50 | fi | ||
51 | |||
52 | cache="$(curl -v -X "POST" "$link_to_api" --data "{\"name\":\"Test\",\"other\":\"Test\"}" 2>&1 | grep "error")" | ||
53 | if [ "" == "$cache" ] | ||
54 | then | ||
55 | exit 1 | ||
56 | fi | ||
57 | |||
58 | cache="$(curl -v -X "POST" "$link_to_api" --data "{\"nam\":\"Test\"}" 2>&1 | grep "error")" | ||
59 | if [ "" == "$cache" ] | ||
60 | then | ||
61 | exit 1 | ||
62 | fi | ||
63 | |||
64 | cache="$(curl -v -X "POST" "$link_to_api" --data "{\"name\":123}" 2>&1 | grep "error")" | ||
65 | if [ "" == "$cache" ] | ||
66 | then | ||
67 | exit 1 | ||
68 | fi | ||
69 | |||
70 | cache="$(curl -v -X "POST" "$link_to_api" --data "{\"name\":""}" 2>&1 | grep "error")" | ||
71 | if [ "" == "$cache" ] | ||
72 | then | ||
73 | exit 1 | ||
74 | fi | ||
75 | |||
76 | |||
77 | #Test GET (multiple identities) for success and error json | ||
78 | cache="$(curl --silent "$link_to_api" | grep "error")" | ||
79 | if [ "" != "$cache" ] | ||
80 | then | ||
81 | exit 1 | ||
82 | fi | ||
83 | |||
84 | |||
85 | id="$(gnunet-identity -d | grep "Test - " | sed "s/Test - //g")" | ||
86 | #Test GET (one identity) for success and error json | ||
87 | cache="$(curl --silent "${link_to_api}?pubkey=$id" | grep "error")" | ||
88 | if [ "" != "$cache" ] | ||
89 | then | ||
90 | exit 1 | ||
91 | fi | ||
92 | |||
93 | |||
94 | #Test DELETE success code, error response code and error json | ||
95 | #echo "Next tests for DELETE will probably fail when POST fails" | ||
96 | cache="$(curl -v -X "DELETE" "${link_to_api}?pubkey=$id" 2>&1 | grep "HTTP/1.1 404")" | ||
97 | if [ "" != "$cache" ] | ||
98 | then | ||
99 | exit 1 | ||
100 | fi | ||
101 | |||
102 | curl --silent -X "POST" "$link_to_api" --data "{\"name\":\"Test\"}" | ||
103 | id="$(gnunet-identity -d | grep "Test - " | sed "s/Test - //g")" | ||
104 | |||
105 | cache="$(curl -v -X "DELETE" "${link_to_api}?pubkey=df1" 2>&1 | grep "HTTP/1.1 404")" | ||
106 | if [ "" == "$cache" ] | ||
107 | then | ||
108 | exit 1 | ||
109 | fi | ||
110 | |||
111 | cache="$(curl -v -X "DELETE" "${link_to_api}?pubke=$id" 2>&1 | grep "error")" | ||
112 | if [ "" == "$cache" ] | ||
113 | then | ||
114 | exit 1 | ||
115 | fi | ||
116 | |||
117 | #Test PUT success code, error response codes and error json | ||
118 | cache="$(curl -v -X "PUT" "${link_to_api}" --data "{\"newname\":\"NewTest\",\"pubkey\":\"${id}\"}" 2>&1 | grep "HTTP/1.1 204")" | ||
119 | if [ "" == "$cache" ] | ||
120 | then | ||
121 | exit 1 | ||
122 | fi | ||
123 | |||
124 | cache="$(curl -v -X "PUT" "${link_to_api}" --data "{\"newname\":\"NewNewTest\",\"pubkey\":\"${id}1\"}" 2>&1 | grep "HTTP/1.1 404")" | ||
125 | if [ "" == "$cache" ] | ||
126 | then | ||
127 | exit 1 | ||
128 | fi | ||
129 | |||
130 | # feature: you can rename your identity with its own name. | ||
131 | # cache="$(curl -v -X "PUT" "$link_to_api" --data "{\"newname\":\"NewTest\",\"pubkey\":\"${id}\"}" 2>&1 | grep "error")" | ||
132 | # if [ "" == "$cache" ] | ||
133 | # then | ||
134 | # exit 1 | ||
135 | # fi | ||
136 | |||
137 | |||
138 | cache="$(curl -v -X "PUT" "$link_to_api" 2>&1 | grep "error")" | ||
139 | if [ "" == "$cache" ] | ||
140 | then | ||
141 | exit 1 | ||
142 | fi | ||
143 | |||
144 | cache="$(curl -v -X "PUT" "$link_to_api" --data "wrong" 2>&1 | grep "error")" | ||
145 | if [ "" == "$cache" ] | ||
146 | then | ||
147 | exit 1 | ||
148 | fi | ||
149 | |||
150 | cache="$(curl -v -X "PUT" "$link_to_api" --data "[{}]" 2>&1 | grep "error")" | ||
151 | if [ "" == "$cache" ] | ||
152 | then | ||
153 | exit 1 | ||
154 | fi | ||
155 | |||
156 | cache="$(curl -v -X "PUT" "$link_to_api" --data "{\"newname\":\"Test\",\"other\":\"Test\",\"pubkey\":\"${id}\"}" 2>&1 | grep "error")" | ||
157 | if [ "" == "$cache" ] | ||
158 | then | ||
159 | exit 1 | ||
160 | fi | ||
161 | |||
162 | cache="$(curl -v -X "PUT" "$link_to_api" --data "{\"newnam\":\"Test\",\"pubkey\":\"${id}\"}" 2>&1 | grep "error")" | ||
163 | if [ "" == "$cache" ] | ||
164 | then | ||
165 | exit 1 | ||
166 | fi | ||
167 | |||
168 | cache="$(curl -v -X "PUT" "$link_to_api" --data "{\"newname\":\"Test\",\"pubke\":\"${id}\"}" 2>&1 | grep "error")" | ||
169 | if [ "" == "$cache" ] | ||
170 | then | ||
171 | exit 1 | ||
172 | fi | ||
173 | |||
174 | cache="$(curl -v -X "PUT" "$link_to_api" --data "{\"newname\":123,\"pubkey\":\"${id}\"}" 2>&1 | grep "error")" | ||
175 | if [ "" == "$cache" ] | ||
176 | then | ||
177 | exit 1 | ||
178 | fi | ||
179 | |||
180 | cache="$(curl -v -X "PUT" "$link_to_api" --data "{\"newname\":"",\"pubkey\":\"${id}\"}" 2>&1 | grep "error")" | ||
181 | if [ "" == "$cache" ] | ||
182 | then | ||
183 | exit 1 | ||
184 | fi | ||
185 | #TODO Missing subsystem test | ||
186 | |||
187 | #Missing OPTIONS success - nothing can really go wrong here | ||
188 | |||
189 | #Test wrong url | ||
190 | cache="$(curl -v "$wrong_link" 2>&1 | grep "HTTP/1.1 404")" | ||
191 | if [ "" == "$cache" ] | ||
192 | then | ||
193 | exit 1 | ||
194 | fi | ||
195 | |||
196 | cache="$(curl -X "PUT" -v "$wrong_link" --data "{\"newname\":\"Testing\",\"pubkey\":\"${id}\"}" 2>&1 | grep "HTTP/1.1 404")" | ||
197 | if [ "" == "$cache" ] | ||
198 | then | ||
199 | exit 1 | ||
200 | fi | ||
201 | |||
202 | cache="$(curl -X "POST" -v "$wrong_link?pubkey=$id" --data "{\"name\":\"Test\"}" 2>&1 | grep "HTTP/1.1 404")" | ||
203 | if [ "" == "$cache" ] | ||
204 | then | ||
205 | exit 1 | ||
206 | fi | ||
207 | |||
208 | cache="$(curl -X "DELETE" -v "${wrong_link}?pubkey=$id" 2>&1 | grep "HTTP/1.1 404")" | ||
209 | if [ "" == "$cache" ] | ||
210 | then | ||
211 | exit 1 | ||
212 | fi | ||
213 | |||
214 | gnunet-identity -D NewTest | ||
215 | |||
216 | exit 0 | ||