Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 2014-2025 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU Affero General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file src/backend/taler-merchant-httpd_dispatcher.c
18 : * @brief map requested URL and method to the respective request handler
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include "taler-merchant-httpd_get-config.h"
23 : #include "taler-merchant-httpd_get-exchanges.h"
24 : #include "taler-merchant-httpd_dispatcher.h"
25 : #include "taler-merchant-httpd_get-orders-ORDER_ID.h"
26 : #include "taler-merchant-httpd_get-sessions-SESSION_ID.h"
27 : #include "taler-merchant-httpd_get-products-IMAGE_HASH-image.h"
28 : #include "taler-merchant-httpd_get-templates-TEMPLATE_ID.h"
29 : #include "taler-merchant-httpd_mhd.h"
30 : #include "taler-merchant-httpd_delete-private-accounts-H_WIRE.h"
31 : #include "taler-merchant-httpd_delete-private-categories-CATEGORY_ID.h"
32 : #include "taler-merchant-httpd_delete-private-units-UNIT.h"
33 : #include "taler-merchant-httpd_delete-management-instances-INSTANCE.h"
34 : #include "taler-merchant-httpd_delete-private-token.h"
35 : #include "taler-merchant-httpd_delete-private-tokens-SERIAL.h"
36 : #include "taler-merchant-httpd_delete-private-products-PRODUCT_ID.h"
37 : #include "taler-merchant-httpd_delete-private-orders-ORDER_ID.h"
38 : #include "taler-merchant-httpd_delete-private-otp-devices-DEVICE_ID.h"
39 : #include "taler-merchant-httpd_delete-private-templates-TEMPLATE_ID.h"
40 : #include "taler-merchant-httpd_delete-private-tokenfamilies-TOKEN_FAMILY_SLUG.h"
41 : #include "taler-merchant-httpd_delete-private-transfers-TID.h"
42 : #include "taler-merchant-httpd_delete-private-webhooks-WEBHOOK_ID.h"
43 : #include "taler-merchant-httpd_get-private-accounts.h"
44 : #include "taler-merchant-httpd_get-private-accounts-H_WIRE.h"
45 : #include "taler-merchant-httpd_get-private-categories.h"
46 : #include "taler-merchant-httpd_get-private-categories-CATEGORY_ID.h"
47 : #include "taler-merchant-httpd_get-private-units.h"
48 : #include "taler-merchant-httpd_get-private-units-UNIT.h"
49 : #include "taler-merchant-httpd_get-private-incoming.h"
50 : #include "taler-merchant-httpd_get-private-incoming-ID.h"
51 : #include "taler-merchant-httpd_get-management-instances.h"
52 : #include "taler-merchant-httpd_get-management-instances-INSTANCE.h"
53 : #include "taler-merchant-httpd_get-private-kyc.h"
54 : #include "taler-merchant-httpd_get-private-tokens.h"
55 : #include "taler-merchant-httpd_get-private-pos.h"
56 : #include "taler-merchant-httpd_get-private-products.h"
57 : #include "taler-merchant-httpd_get-private-products-PRODUCT_ID.h"
58 : #include "taler-merchant-httpd_get-private-orders.h"
59 : #include "taler-merchant-httpd_get-private-orders-ORDER_ID.h"
60 : #include "taler-merchant-httpd_get-private-otp-devices.h"
61 : #include "taler-merchant-httpd_get-private-otp-devices-DEVICE_ID.h"
62 : #include "taler-merchant-httpd_get-private-statistics-amount-SLUG.h"
63 : #include "taler-merchant-httpd_get-private-statistics-counter-SLUG.h"
64 : #include "taler-merchant-httpd_get-private-statistics-report-transactions.h"
65 : #include "taler-merchant-httpd_get-private-templates.h"
66 : #include "taler-merchant-httpd_get-private-templates-TEMPLATE_ID.h"
67 : #include "taler-merchant-httpd_get-private-tokenfamilies.h"
68 : #include "taler-merchant-httpd_get-private-tokenfamilies-TOKEN_FAMILY_SLUG.h"
69 : #include "taler-merchant-httpd_get-private-transfers.h"
70 : #include "taler-merchant-httpd_get-private-webhooks.h"
71 : #include "taler-merchant-httpd_get-private-webhooks-WEBHOOK_ID.h"
72 : #include "taler-merchant-httpd_patch-private-accounts-H_WIRE.h"
73 : #include "taler-merchant-httpd_patch-private-categories-CATEGORY_ID.h"
74 : #include "taler-merchant-httpd_patch-private-units-UNIT.h"
75 : #include "taler-merchant-httpd_patch-management-instances-INSTANCE.h"
76 : #include "taler-merchant-httpd_patch-private-orders-ORDER_ID-forget.h"
77 : #include "taler-merchant-httpd_patch-private-otp-devices-DEVICE_ID.h"
78 : #include "taler-merchant-httpd_patch-private-products-PRODUCT_ID.h"
79 : #include "taler-merchant-httpd_patch-private-templates-TEMPLATE_ID.h"
80 : #include "taler-merchant-httpd_patch-private-tokenfamilies-TOKEN_FAMILY_SLUG.h"
81 : #include "taler-merchant-httpd_patch-private-webhooks-WEBHOOK_ID.h"
82 : #include "taler-merchant-httpd_post-private-accounts.h"
83 : #include "taler-merchant-httpd_post-private-categories.h"
84 : #include "taler-merchant-httpd_post-private-units.h"
85 : #include "taler-merchant-httpd_post-management-instances.h"
86 : #include "taler-merchant-httpd_post-management-instances-INSTANCE-auth.h"
87 : #include "taler-merchant-httpd_post-private-token.h"
88 : #include "taler-merchant-httpd_post-private-otp-devices.h"
89 : #include "taler-merchant-httpd_post-private-orders.h"
90 : #include "taler-merchant-httpd_post-private-orders-ORDER_ID-collect.h"
91 : #include "taler-merchant-httpd_post-private-orders-ORDER_ID-refund.h"
92 : #include "taler-merchant-httpd_post-private-orders-ORDER_ID-refund-external.h"
93 : #include "taler-merchant-httpd_post-private-products.h"
94 : #include "taler-merchant-httpd_post-private-products-PRODUCT_ID-lock.h"
95 : #include "taler-merchant-httpd_post-private-templates.h"
96 : #include "taler-merchant-httpd_post-private-tokenfamilies.h"
97 : #include "taler-merchant-httpd_post-private-transfers.h"
98 : #include "taler-merchant-httpd_post-private-webhooks.h"
99 : #include "taler-merchant-httpd_post-private-accounts-H_WIRE-kycauth.h"
100 : #include "taler-merchant-httpd_post-private-accept-tos-early.h"
101 : #include "taler-merchant-httpd_post-challenge-ID.h"
102 : #include "taler-merchant-httpd_post-challenge-ID-confirm.h"
103 : #include "taler-merchant-httpd_post-orders-ORDER_ID-abort.h"
104 : #include "taler-merchant-httpd_post-orders-ORDER_ID-claim.h"
105 : #include "taler-merchant-httpd_post-orders-ORDER_ID-paid.h"
106 : #include "taler-merchant-httpd_post-orders-ORDER_ID-pay.h"
107 : #include "taler-merchant-httpd_post-orders-ORDER_ID-unclaim.h"
108 : #include "taler-merchant-httpd_post-templates-TEMPLATE_ID.h"
109 : #include "taler-merchant-httpd_post-orders-ORDER_ID-refund.h"
110 : #include "taler-merchant-httpd_get-webui.h"
111 : #include "taler-merchant-httpd_statics.h"
112 : #include "taler-merchant-httpd_get-terms.h"
113 : #include "taler-merchant-httpd_post-reports-REPORT_ID.h"
114 : #include "taler-merchant-httpd_delete-private-reports-REPORT_ID.h"
115 : #include "taler-merchant-httpd_get-private-reports-REPORT_ID.h"
116 : #include "taler-merchant-httpd_get-private-reports.h"
117 : #include "taler-merchant-httpd_patch-private-reports-REPORT_ID.h"
118 : #include "taler-merchant-httpd_post-private-reports.h"
119 : #include "taler-merchant-httpd_delete-private-pots-POT_ID.h"
120 : #include "taler-merchant-httpd_get-private-pots-POT_ID.h"
121 : #include "taler-merchant-httpd_get-private-pots.h"
122 : #include "taler-merchant-httpd_patch-private-pots-POT_ID.h"
123 : #include "taler-merchant-httpd_post-private-pots.h"
124 : #include "taler-merchant-httpd_get-private-groups.h"
125 : #include "taler-merchant-httpd_post-private-groups.h"
126 : #include "taler-merchant-httpd_patch-private-groups-GROUP_ID.h"
127 : #include "taler-merchant-httpd_delete-private-groups-GROUP_ID.h"
128 : #include "taler-merchant-httpd_get-private-donau.h"
129 : #include "taler-merchant-httpd_post-private-donau.h"
130 : #include "taler-merchant-httpd_delete-private-donau-DONAU_SERIAL.h"
131 :
132 :
133 : /**
134 : * Handle a OPTIONS "*" request.
135 : *
136 : * @param rh context of the handler
137 : * @param connection the MHD connection to handle
138 : * @param[in,out] hc context with further information about the request
139 : * @return MHD result code
140 : */
141 : static enum MHD_Result
142 0 : handle_server_options (const struct TMH_RequestHandler *rh,
143 : struct MHD_Connection *connection,
144 : struct TMH_HandlerContext *hc)
145 : {
146 : (void) rh;
147 : (void) hc;
148 0 : return TALER_MHD_reply_cors_preflight (connection);
149 : }
150 :
151 :
152 : /**
153 : * Generates the response for "/", redirecting the
154 : * client to the "/webui/" from where we serve the SPA.
155 : *
156 : * @param rh request handler
157 : * @param connection MHD connection
158 : * @param hc handler context
159 : * @return MHD result code
160 : */
161 : static enum MHD_Result
162 1 : spa_redirect (const struct TMH_RequestHandler *rh,
163 : struct MHD_Connection *connection,
164 : struct TMH_HandlerContext *hc)
165 : {
166 1 : const char *text = "Redirecting to /webui/";
167 : struct MHD_Response *response;
168 : char *dst;
169 :
170 1 : response = MHD_create_response_from_buffer (strlen (text),
171 : (void *) text,
172 : MHD_RESPMEM_PERSISTENT);
173 1 : if (NULL == response)
174 : {
175 0 : GNUNET_break (0);
176 0 : return MHD_NO;
177 : }
178 1 : TALER_MHD_add_global_headers (response,
179 : true);
180 1 : GNUNET_break (MHD_YES ==
181 : MHD_add_response_header (response,
182 : MHD_HTTP_HEADER_CONTENT_TYPE,
183 : "text/plain"));
184 1 : if ( (NULL == hc->instance) ||
185 1 : (0 == strcmp ("admin",
186 1 : hc->instance->settings.id)) )
187 1 : dst = GNUNET_strdup ("/webui/");
188 : else
189 0 : GNUNET_asprintf (&dst,
190 : "/instances/%s/webui/",
191 0 : hc->instance->settings.id);
192 1 : if (MHD_NO ==
193 1 : MHD_add_response_header (response,
194 : MHD_HTTP_HEADER_LOCATION,
195 : dst))
196 : {
197 0 : GNUNET_break (0);
198 0 : MHD_destroy_response (response);
199 0 : GNUNET_free (dst);
200 0 : return MHD_NO;
201 : }
202 1 : GNUNET_free (dst);
203 :
204 : {
205 : enum MHD_Result ret;
206 :
207 1 : ret = MHD_queue_response (connection,
208 : MHD_HTTP_FOUND,
209 : response);
210 1 : MHD_destroy_response (response);
211 1 : return ret;
212 : }
213 : }
214 :
215 :
216 : /**
217 : * Determine the group of request handlers to call for the
218 : * given URL. Removes a possible prefix from @a purl by advancing
219 : * the pointer.
220 : *
221 : * @param[in,out] urlp pointer to the URL to analyze and update
222 : * @param[out] is_public set to true if these are public handlers
223 : * @return handler group to consider for the given URL
224 : */
225 : static const struct TMH_RequestHandler *
226 1144 : determine_handler_group (const char **urlp,
227 : bool *is_public)
228 : {
229 : static struct TMH_RequestHandler management_handlers[] = {
230 : /* GET /instances */
231 : {
232 : .url_prefix = "/instances",
233 : .method = MHD_HTTP_METHOD_GET,
234 : .permission = "instances-write",
235 : .skip_instance = true,
236 : .default_only = true,
237 : .handler = &TMH_private_get_instances
238 : },
239 : /* POST /instances */
240 : {
241 : .url_prefix = "/instances",
242 : .method = MHD_HTTP_METHOD_POST,
243 : .permission = "instances-write",
244 : .skip_instance = true,
245 : .default_only = true,
246 : .handler = &TMH_private_post_instances,
247 : /* allow instance data of up to 8 MB, that should be plenty;
248 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
249 : would require further changes to the allocation logic
250 : in the code... */
251 : .max_upload = 1024 * 1024 * 8
252 : },
253 : /* GET /instances/$ID/ */
254 : {
255 : .url_prefix = "/instances/",
256 : .method = MHD_HTTP_METHOD_GET,
257 : .permission = "instances-write",
258 : .skip_instance = true,
259 : .default_only = true,
260 : .have_id_segment = true,
261 : .handler = &TMH_private_get_instances_default_ID
262 : },
263 : /* DELETE /instances/$ID */
264 : {
265 : .url_prefix = "/instances/",
266 : .method = MHD_HTTP_METHOD_DELETE,
267 : .permission = "instances-write",
268 : .skip_instance = true,
269 : .default_only = true,
270 : .have_id_segment = true,
271 : .handler = &TMH_private_delete_instances_default_ID
272 : },
273 : /* PATCH /instances/$ID */
274 : {
275 : .url_prefix = "/instances/",
276 : .method = MHD_HTTP_METHOD_PATCH,
277 : .permission = "instances-write",
278 : .skip_instance = true,
279 : .default_only = true,
280 : .have_id_segment = true,
281 : .handler = &TMH_private_patch_instances_default_ID,
282 : /* allow instance data of up to 8 MB, that should be plenty;
283 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
284 : would require further changes to the allocation logic
285 : in the code... */
286 : .max_upload = 1024 * 1024 * 8
287 : },
288 : /* POST /auth: */
289 : {
290 : .url_prefix = "/instances/",
291 : .url_suffix = "auth",
292 : .method = MHD_HTTP_METHOD_POST,
293 : .permission = "instances-auth-write",
294 : .skip_instance = true,
295 : .default_only = true,
296 : .have_id_segment = true,
297 : .handler = &TMH_private_post_instances_default_ID_auth,
298 : /* Body should be pretty small. */
299 : .max_upload = 1024 * 1024
300 : },
301 : /* GET /kyc: */
302 : {
303 : .url_prefix = "/instances/",
304 : .url_suffix = "kyc",
305 : .method = MHD_HTTP_METHOD_GET,
306 : .permission = "instances-kyc-read",
307 : .skip_instance = true,
308 : .default_only = true,
309 : .have_id_segment = true,
310 : .handler = &TMH_private_get_instances_default_ID_kyc,
311 : },
312 : {
313 : .url_prefix = NULL
314 : }
315 : };
316 :
317 : static struct TMH_RequestHandler private_handlers[] = {
318 : /* GET /instances/$ID/: */
319 : {
320 : .url_prefix = "/",
321 : .method = MHD_HTTP_METHOD_GET,
322 : .permission = "instances-read",
323 : .handler = &TMH_private_get_instances_ID
324 : },
325 : /* DELETE /instances/$ID/: */
326 : {
327 : .url_prefix = "/",
328 : .method = MHD_HTTP_METHOD_DELETE,
329 : .permission = "instances-write",
330 : .allow_deleted_instance = true,
331 : .handler = &TMH_private_delete_instances_ID
332 : },
333 : /* PATCH /instances/$ID/: */
334 : {
335 : .url_prefix = "/",
336 : .method = MHD_HTTP_METHOD_PATCH,
337 : .handler = &TMH_private_patch_instances_ID,
338 : .permission = "instances-write",
339 : .allow_deleted_instance = true,
340 : /* allow instance data of up to 8 MB, that should be plenty;
341 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
342 : would require further changes to the allocation logic
343 : in the code... */
344 : .max_upload = 1024 * 1024 * 8
345 : },
346 : /* POST /auth: */
347 : {
348 : .url_prefix = "/auth",
349 : .method = MHD_HTTP_METHOD_POST,
350 : .handler = &TMH_private_post_instances_ID_auth,
351 : .permission = "auth-write",
352 : /* Body should be pretty small. */
353 : .max_upload = 1024 * 1024,
354 : },
355 : /* GET /kyc: */
356 : {
357 : .url_prefix = "/kyc",
358 : .method = MHD_HTTP_METHOD_GET,
359 : .permission = "kyc-read",
360 : .handler = &TMH_private_get_instances_ID_kyc,
361 : },
362 : /* GET /pos: */
363 : {
364 : .url_prefix = "/pos",
365 : .method = MHD_HTTP_METHOD_GET,
366 : .permission = "pos-read",
367 : .handler = &TMH_private_get_pos
368 : },
369 : /* GET /categories: */
370 : {
371 : .url_prefix = "/categories",
372 : .method = MHD_HTTP_METHOD_GET,
373 : .permission = "categories-read",
374 : .handler = &TMH_private_get_categories
375 : },
376 : /* POST /categories: */
377 : {
378 : .url_prefix = "/categories",
379 : .method = MHD_HTTP_METHOD_POST,
380 : .permission = "categories-write",
381 : .handler = &TMH_private_post_categories,
382 : /* allow category data of up to 8 kb, that should be plenty */
383 : .max_upload = 1024 * 8
384 : },
385 : /* GET /categories/$ID: */
386 : {
387 : .url_prefix = "/categories/",
388 : .method = MHD_HTTP_METHOD_GET,
389 : .permission = "categories-read",
390 : .have_id_segment = true,
391 : .allow_deleted_instance = true,
392 : .handler = &TMH_private_get_categories_ID
393 : },
394 : /* DELETE /categories/$ID: */
395 : {
396 : .url_prefix = "/categories/",
397 : .method = MHD_HTTP_METHOD_DELETE,
398 : .permission = "categories-write",
399 : .have_id_segment = true,
400 : .allow_deleted_instance = true,
401 : .handler = &TMH_private_delete_categories_ID
402 : },
403 : /* PATCH /categories/$ID/: */
404 : {
405 : .url_prefix = "/categories/",
406 : .method = MHD_HTTP_METHOD_PATCH,
407 : .permission = "categories-write",
408 : .have_id_segment = true,
409 : .allow_deleted_instance = true,
410 : .handler = &TMH_private_patch_categories_ID,
411 : /* allow category data of up to 8 kb, that should be plenty */
412 : .max_upload = 1024 * 8
413 : },
414 : /* GET /units: */
415 : {
416 : .url_prefix = "/units",
417 : .method = MHD_HTTP_METHOD_GET,
418 : .permission = "units-read",
419 : .handler = &TMH_private_get_units
420 : },
421 : /* POST /units: */
422 : {
423 : .url_prefix = "/units",
424 : .method = MHD_HTTP_METHOD_POST,
425 : .permission = "units-write",
426 : .handler = &TMH_private_post_units,
427 : .max_upload = 1024 * 8
428 : },
429 : /* GET /units/$UNIT: */
430 : {
431 : .url_prefix = "/units/",
432 : .method = MHD_HTTP_METHOD_GET,
433 : .have_id_segment = true,
434 : .allow_deleted_instance = true,
435 : .permission = "units-read",
436 : .handler = &TMH_private_get_units_ID
437 : },
438 : /* DELETE /units/$UNIT: */
439 : {
440 : .url_prefix = "/units/",
441 : .method = MHD_HTTP_METHOD_DELETE,
442 : .permission = "units-write",
443 : .have_id_segment = true,
444 : .allow_deleted_instance = true,
445 : .handler = &TMH_private_delete_units_ID
446 : },
447 : /* PATCH /units/$UNIT: */
448 : {
449 : .url_prefix = "/units/",
450 : .method = MHD_HTTP_METHOD_PATCH,
451 : .permission = "units-write",
452 : .have_id_segment = true,
453 : .allow_deleted_instance = true,
454 : .handler = &TMH_private_patch_units_ID,
455 : .max_upload = 1024 * 8
456 : },
457 : /* GET /products: */
458 : {
459 : .url_prefix = "/products",
460 : .permission = "products-read",
461 : .method = MHD_HTTP_METHOD_GET,
462 : .handler = &TMH_private_get_products
463 : },
464 : /* POST /products: */
465 : {
466 : .url_prefix = "/products",
467 : .method = MHD_HTTP_METHOD_POST,
468 : .permission = "products-write",
469 : .handler = &TMH_private_post_products,
470 : /* allow product data of up to 8 MB, that should be plenty;
471 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
472 : would require further changes to the allocation logic
473 : in the code... */
474 : .max_upload = 1024 * 1024 * 8
475 : },
476 : /* GET /products/$ID: */
477 : {
478 : .url_prefix = "/products/",
479 : .method = MHD_HTTP_METHOD_GET,
480 : .have_id_segment = true,
481 : .permission = "products-read",
482 : .allow_deleted_instance = true,
483 : .handler = &TMH_private_get_products_ID
484 : },
485 : /* DELETE /products/$ID/: */
486 : {
487 : .url_prefix = "/products/",
488 : .method = MHD_HTTP_METHOD_DELETE,
489 : .have_id_segment = true,
490 : .permission = "products-write",
491 : .allow_deleted_instance = true,
492 : .handler = &TMH_private_delete_products_ID
493 : },
494 : /* PATCH /products/$ID/: */
495 : {
496 : .url_prefix = "/products/",
497 : .method = MHD_HTTP_METHOD_PATCH,
498 : .have_id_segment = true,
499 : .allow_deleted_instance = true,
500 : .permission = "products-write",
501 : .handler = &TMH_private_patch_products_ID,
502 : /* allow product data of up to 8 MB, that should be plenty;
503 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
504 : would require further changes to the allocation logic
505 : in the code... */
506 : .max_upload = 1024 * 1024 * 8
507 : },
508 : /* POST /products/$ID/lock: */
509 : {
510 : .url_prefix = "/products/",
511 : .url_suffix = "lock",
512 : .method = MHD_HTTP_METHOD_POST,
513 : .have_id_segment = true,
514 : .permission = "products-lock",
515 : .handler = &TMH_private_post_products_ID_lock,
516 : /* the body should be pretty small, allow 1 MB of upload
517 : to set a conservative bound for sane wallets */
518 : .max_upload = 1024 * 1024
519 : },
520 : /* POST /orders: */
521 : {
522 : .url_prefix = "/orders",
523 : .method = MHD_HTTP_METHOD_POST,
524 : .permission = "orders-write",
525 : .handler = &TMH_private_post_orders,
526 : /* allow contracts of up to 8 MB, that should be plenty;
527 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
528 : would require further changes to the allocation logic
529 : in the code... */
530 : .max_upload = 1024 * 1024 * 8
531 : },
532 : /* GET /orders/$ID: */
533 : {
534 : .url_prefix = "/orders/",
535 : .method = MHD_HTTP_METHOD_GET,
536 : .permission = "orders-read",
537 : .have_id_segment = true,
538 : .allow_deleted_instance = true,
539 : .handler = &TMH_private_get_orders_ID
540 : },
541 : /* GET /orders: */
542 : {
543 : .url_prefix = "/orders",
544 : .method = MHD_HTTP_METHOD_GET,
545 : .permission = "orders-read",
546 : .allow_deleted_instance = true,
547 : .handler = &TMH_private_get_orders
548 : },
549 : /* POST /orders/$ID/refund: */
550 : {
551 : .url_prefix = "/orders/",
552 : .url_suffix = "refund",
553 : .method = MHD_HTTP_METHOD_POST,
554 : .have_id_segment = true,
555 : .permission = "orders-refund",
556 : .handler = &TMH_private_post_orders_ID_refund,
557 : /* the body should be pretty small, allow 1 MB of upload
558 : to set a conservative bound for sane wallets */
559 : .max_upload = 1024 * 1024
560 : },
561 : /* POST /orders/$ID/refund-external: */
562 : {
563 : .url_prefix = "/orders/",
564 : .url_suffix = "refund-external",
565 : .method = MHD_HTTP_METHOD_POST,
566 : .have_id_segment = true,
567 : .permission = "orders-refund",
568 : .handler = &TMH_private_post_orders_ID_refund_external,
569 : /* the body should be pretty small, allow 1 MB of upload
570 : to set a conservative bound for sane wallets */
571 : .max_upload = 1024 * 1024
572 : },
573 : /* POST /orders/$ID/collect: */
574 : {
575 : .url_prefix = "/orders/",
576 : .url_suffix = "collect",
577 : .method = MHD_HTTP_METHOD_POST,
578 : .have_id_segment = true,
579 : .permission = "orders-write",
580 : .handler = &TMH_private_post_orders_ID_collect,
581 : /* the body should be pretty small, allow 1 MB of upload
582 : to set a conservative bound for sane wallets */
583 : .max_upload = 1024 * 1024
584 : },
585 : /* PATCH /orders/$ID/forget: */
586 : {
587 : .url_prefix = "/orders/",
588 : .url_suffix = "forget",
589 : .method = MHD_HTTP_METHOD_PATCH,
590 : .permission = "orders-write",
591 : .have_id_segment = true,
592 : .allow_deleted_instance = true,
593 : .handler = &TMH_private_patch_orders_ID_forget,
594 : /* the body should be pretty small, allow 1 MB of upload
595 : to set a conservative bound for sane wallets */
596 : .max_upload = 1024 * 1024
597 : },
598 : /* DELETE /orders/$ID: */
599 : {
600 : .url_prefix = "/orders/",
601 : .method = MHD_HTTP_METHOD_DELETE,
602 : .permission = "orders-write",
603 : .have_id_segment = true,
604 : .allow_deleted_instance = true,
605 : .handler = &TMH_private_delete_orders_ID
606 : },
607 : /* POST /transfers: */
608 : {
609 : .url_prefix = "/transfers",
610 : .method = MHD_HTTP_METHOD_POST,
611 : .allow_deleted_instance = true,
612 : .handler = &TMH_private_post_transfers,
613 : .permission = "transfers-write",
614 : /* the body should be pretty small, allow 1 MB of upload
615 : to set a conservative bound for sane wallets */
616 : .max_upload = 1024 * 1024
617 : },
618 : /* DELETE /transfers/$ID: */
619 : {
620 : .url_prefix = "/transfers/",
621 : .method = MHD_HTTP_METHOD_DELETE,
622 : .permission = "transfers-write",
623 : .allow_deleted_instance = true,
624 : .handler = &TMH_private_delete_transfers_ID,
625 : .have_id_segment = true,
626 : /* the body should be pretty small, allow 1 MB of upload
627 : to set a conservative bound for sane wallets */
628 : .max_upload = 1024 * 1024
629 : },
630 : /* GET /transfers: */
631 : {
632 : .url_prefix = "/transfers",
633 : .permission = "transfers-read",
634 : .method = MHD_HTTP_METHOD_GET,
635 : .allow_deleted_instance = true,
636 : .handler = &TMH_private_get_transfers
637 : },
638 : /* GET /incoming: */
639 : {
640 : .url_prefix = "/incoming",
641 : .permission = "transfers-read",
642 : .method = MHD_HTTP_METHOD_GET,
643 : .allow_deleted_instance = true,
644 : .handler = &TMH_private_get_incoming
645 : },
646 : /* GET /incoming/$ID: */
647 : {
648 : .url_prefix = "/incoming/",
649 : .permission = "transfers-read",
650 : .method = MHD_HTTP_METHOD_GET,
651 : .allow_deleted_instance = true,
652 : .have_id_segment = true,
653 : .handler = &TMH_private_get_incoming_ID
654 : },
655 : /* POST /otp-devices: */
656 : {
657 : .url_prefix = "/otp-devices",
658 : .permission = "otp-devices-write",
659 : .method = MHD_HTTP_METHOD_POST,
660 : .handler = &TMH_private_post_otp_devices
661 : },
662 : /* GET /otp-devices: */
663 : {
664 : .url_prefix = "/otp-devices",
665 : .permission = "otp-devices-read",
666 : .method = MHD_HTTP_METHOD_GET,
667 : .handler = &TMH_private_get_otp_devices
668 : },
669 : /* GET /otp-devices/$ID: */
670 : {
671 : .url_prefix = "/otp-devices/",
672 : .method = MHD_HTTP_METHOD_GET,
673 : .permission = "otp-devices-read",
674 : .have_id_segment = true,
675 : .handler = &TMH_private_get_otp_devices_ID
676 : },
677 : /* DELETE /otp-devices/$ID: */
678 : {
679 : .url_prefix = "/otp-devices/",
680 : .method = MHD_HTTP_METHOD_DELETE,
681 : .permission = "otp-devices-write",
682 : .have_id_segment = true,
683 : .handler = &TMH_private_delete_otp_devices_ID
684 : },
685 : /* PATCH /otp-devices/$ID: */
686 : {
687 : .url_prefix = "/otp-devices/",
688 : .method = MHD_HTTP_METHOD_PATCH,
689 : .permission = "otp-devices-write",
690 : .have_id_segment = true,
691 : .handler = &TMH_private_patch_otp_devices_ID
692 : },
693 : /* POST /templates: */
694 : {
695 : .url_prefix = "/templates",
696 : .method = MHD_HTTP_METHOD_POST,
697 : .permission = "templates-write",
698 : .handler = &TMH_private_post_templates,
699 : /* allow template data of up to 8 MB, that should be plenty;
700 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
701 : would require further changes to the allocation logic
702 : in the code... */
703 : .max_upload = 1024 * 1024 * 8
704 : },
705 : /* GET /templates: */
706 : {
707 : .url_prefix = "/templates",
708 : .permission = "templates-read",
709 : .method = MHD_HTTP_METHOD_GET,
710 : .handler = &TMH_private_get_templates
711 : },
712 : /* GET /templates/$ID/: */
713 : {
714 : .url_prefix = "/templates/",
715 : .method = MHD_HTTP_METHOD_GET,
716 : .permission = "templates-read",
717 : .have_id_segment = true,
718 : .allow_deleted_instance = true,
719 : .handler = &TMH_private_get_templates_ID
720 : },
721 : /* DELETE /templates/$ID/: */
722 : {
723 : .url_prefix = "/templates/",
724 : .method = MHD_HTTP_METHOD_DELETE,
725 : .permission = "templates-write",
726 : .have_id_segment = true,
727 : .allow_deleted_instance = true,
728 : .handler = &TMH_private_delete_templates_ID
729 : },
730 : /* PATCH /templates/$ID/: */
731 : {
732 : .url_prefix = "/templates/",
733 : .method = MHD_HTTP_METHOD_PATCH,
734 : .permission = "templates-write",
735 : .have_id_segment = true,
736 : .allow_deleted_instance = true,
737 : .handler = &TMH_private_patch_templates_ID,
738 : /* allow template data of up to 8 MB, that should be plenty;
739 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
740 : would require further changes to the allocation logic
741 : in the code... */
742 : .max_upload = 1024 * 1024 * 8
743 : },
744 :
745 : /* POST /pots: */
746 : {
747 : .url_prefix = "/pots",
748 : .method = MHD_HTTP_METHOD_POST,
749 : .permission = "pots-write",
750 : .handler = &TMH_private_post_pots,
751 : },
752 : /* GET /pots: */
753 : {
754 : .url_prefix = "/pots",
755 : .permission = "pots-read",
756 : .method = MHD_HTTP_METHOD_GET,
757 : .handler = &TMH_private_get_pots
758 : },
759 : /* DELETE /pots/$ID: */
760 : {
761 : .url_prefix = "/pots/",
762 : .method = MHD_HTTP_METHOD_DELETE,
763 : .permission = "pots-write",
764 : .have_id_segment = true,
765 : .handler = &TMH_private_delete_pot
766 : },
767 : /* PATCH /pots/$ID: */
768 : {
769 : .url_prefix = "/pots/",
770 : .method = MHD_HTTP_METHOD_PATCH,
771 : .permission = "pots-write",
772 : .have_id_segment = true,
773 : .handler = &TMH_private_patch_pot,
774 : },
775 :
776 : /* GET /webhooks: */
777 : {
778 : .url_prefix = "/webhooks",
779 : .permission = "webhooks-read",
780 : .method = MHD_HTTP_METHOD_GET,
781 : .handler = &TMH_private_get_webhooks
782 : },
783 : /* POST /webhooks: */
784 : {
785 : .url_prefix = "/webhooks",
786 : .method = MHD_HTTP_METHOD_POST,
787 : .permission = "webhooks-write",
788 : .handler = &TMH_private_post_webhooks,
789 : /* allow webhook data of up to 8 MB, that should be plenty;
790 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
791 : would require further changes to the allocation logic
792 : in the code... */
793 : .max_upload = 1024 * 1024 * 8
794 : },
795 : /* GET /webhooks/$ID/: */
796 : {
797 : .url_prefix = "/webhooks/",
798 : .method = MHD_HTTP_METHOD_GET,
799 : .permission = "webhooks-read",
800 : .have_id_segment = true,
801 : .allow_deleted_instance = true,
802 : .handler = &TMH_private_get_webhooks_ID
803 : },
804 : /* DELETE /webhooks/$ID/: */
805 : {
806 : .url_prefix = "/webhooks/",
807 : .permission = "webhooks-write",
808 : .method = MHD_HTTP_METHOD_DELETE,
809 : .have_id_segment = true,
810 : .allow_deleted_instance = true,
811 : .handler = &TMH_private_delete_webhooks_ID
812 : },
813 : /* PATCH /webhooks/$ID/: */
814 : {
815 : .url_prefix = "/webhooks/",
816 : .method = MHD_HTTP_METHOD_PATCH,
817 : .permission = "webhooks-write",
818 : .have_id_segment = true,
819 : .allow_deleted_instance = true,
820 : .handler = &TMH_private_patch_webhooks_ID,
821 : /* allow webhook data of up to 8 MB, that should be plenty;
822 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
823 : would require further changes to the allocation logic
824 : in the code... */
825 : .max_upload = 1024 * 1024 * 8
826 : },
827 : /* POST /accounts: */
828 : {
829 : .url_prefix = "/accounts",
830 : .method = MHD_HTTP_METHOD_POST,
831 : .permission = "accounts-write",
832 : .handler = &TMH_private_post_account,
833 : /* allow account details of up to 8 kb, that should be plenty */
834 : .max_upload = 1024 * 8
835 : },
836 : /* POST /accounts/H_WIRE/kycauth: */
837 : {
838 : .url_prefix = "/accounts/",
839 : .url_suffix = "kycauth",
840 : .method = MHD_HTTP_METHOD_POST,
841 : .have_id_segment = true,
842 : .permission = "accounts-read",
843 : .handler = &TMH_private_post_accounts_H_WIRE_kycauth,
844 : /* allow exchange URL up to 4 kb, that should be plenty */
845 : .max_upload = 1024 * 4
846 : },
847 : /* POST /accept-tos-early: */
848 : {
849 : .url_prefix = "/accept-tos-early",
850 : .method = MHD_HTTP_METHOD_POST,
851 : .permission = "accounts-write",
852 : .handler = &TMH_private_post_accept_tos_early,
853 : /* allow exchange URL plus terms version up to 4 kb */
854 : .max_upload = 1024 * 4
855 : },
856 : /* PATCH /accounts/$H_WIRE: */
857 : {
858 : .url_prefix = "/accounts/",
859 : .method = MHD_HTTP_METHOD_PATCH,
860 : .permission = "accounts-write",
861 : .handler = &TMH_private_patch_accounts_ID,
862 : .have_id_segment = true,
863 : /* allow account details of up to 8 kb, that should be plenty */
864 : .max_upload = 1024 * 8
865 : },
866 : /* GET /accounts: */
867 : {
868 : .url_prefix = "/accounts",
869 : .permission = "accounts-read",
870 : .method = MHD_HTTP_METHOD_GET,
871 : .handler = &TMH_private_get_accounts
872 : },
873 : /* GET /accounts/$H_WIRE: */
874 : {
875 : .url_prefix = "/accounts/",
876 : .permission = "accounts-read",
877 : .method = MHD_HTTP_METHOD_GET,
878 : .have_id_segment = true,
879 : .handler = &TMH_private_get_accounts_ID
880 : },
881 : /* DELETE /accounts/$H_WIRE: */
882 : {
883 : .url_prefix = "/accounts/",
884 : .permission = "accounts-write",
885 : .method = MHD_HTTP_METHOD_DELETE,
886 : .handler = &TMH_private_delete_account_ID,
887 : .have_id_segment = true
888 : },
889 : /* GET /tokens: */
890 : {
891 : .url_prefix = "/tokens",
892 : .permission = "tokens-read",
893 : .method = MHD_HTTP_METHOD_GET,
894 : .handler = &TMH_private_get_instances_ID_tokens,
895 : },
896 : /* POST /token: */
897 : {
898 : .url_prefix = "/token",
899 : .permission = "token-refresh",
900 : .method = MHD_HTTP_METHOD_POST,
901 : .handler = &TMH_private_post_instances_ID_token,
902 : /* Body should be tiny. */
903 : .max_upload = 1024
904 : },
905 : /* DELETE /tokens/$SERIAL: */
906 : {
907 : .url_prefix = "/tokens/",
908 : .permission = "tokens-write",
909 : .method = MHD_HTTP_METHOD_DELETE,
910 : .handler = &TMH_private_delete_instances_ID_token_SERIAL,
911 : .have_id_segment = true
912 : },
913 : /* DELETE /token: */
914 : {
915 : .url_prefix = "/token",
916 : .method = MHD_HTTP_METHOD_DELETE,
917 : .handler = &TMH_private_delete_instances_ID_token,
918 : .permission = NULL /* No ACL: anyone can delete any token they have */
919 : },
920 : /* GET /tokenfamilies: */
921 : {
922 : .url_prefix = "/tokenfamilies",
923 : .permission = "tokenfamilies-read",
924 : .method = MHD_HTTP_METHOD_GET,
925 : .handler = &TMH_private_get_tokenfamilies
926 : },
927 : /* POST /tokenfamilies: */
928 : {
929 : .url_prefix = "/tokenfamilies",
930 : .permission = "tokenfamilies-write",
931 : .method = MHD_HTTP_METHOD_POST,
932 : .handler = &TMH_private_post_token_families
933 : },
934 : /* GET /tokenfamilies/$SLUG/: */
935 : {
936 : .url_prefix = "/tokenfamilies/",
937 : .method = MHD_HTTP_METHOD_GET,
938 : .permission = "tokenfamilies-read",
939 : .have_id_segment = true,
940 : .handler = &TMH_private_get_tokenfamilies_SLUG
941 : },
942 : /* DELETE /tokenfamilies/$SLUG/: */
943 : {
944 : .url_prefix = "/tokenfamilies/",
945 : .method = MHD_HTTP_METHOD_DELETE,
946 : .permission = "tokenfamilies-write",
947 : .have_id_segment = true,
948 : .handler = &TMH_private_delete_token_families_SLUG
949 : },
950 : /* PATCH /tokenfamilies/$SLUG/: */
951 : {
952 : .url_prefix = "/tokenfamilies/",
953 : .method = MHD_HTTP_METHOD_PATCH,
954 : .permission = "tokenfamilies-write",
955 : .have_id_segment = true,
956 : .handler = &TMH_private_patch_token_family_SLUG,
957 : },
958 :
959 : /* Reports endpoints */
960 : {
961 : .url_prefix = "/reports",
962 : .method = MHD_HTTP_METHOD_GET,
963 : .permission = "reports-read",
964 : .handler = &TMH_private_get_reports,
965 : },
966 : {
967 : .url_prefix = "/reports",
968 : .method = MHD_HTTP_METHOD_POST,
969 : .permission = "reports-write",
970 : .handler = &TMH_private_post_reports,
971 : },
972 : {
973 : .url_prefix = "/reports/",
974 : .method = MHD_HTTP_METHOD_GET,
975 : .handler = &TMH_private_get_report,
976 : .permission = "reports-read",
977 : .have_id_segment = true,
978 : },
979 : {
980 : .url_prefix = "/reports/",
981 : .method = MHD_HTTP_METHOD_PATCH,
982 : .handler = &TMH_private_patch_report,
983 : .permission = "reports-write",
984 : .have_id_segment = true,
985 : },
986 : {
987 : .url_prefix = "/reports/",
988 : .method = MHD_HTTP_METHOD_DELETE,
989 : .handler = &TMH_private_delete_report,
990 : .permission = "reports-write",
991 : .have_id_segment = true,
992 : },
993 :
994 : /* Groups endpoints */
995 : {
996 : .url_prefix = "/groups",
997 : .method = MHD_HTTP_METHOD_GET,
998 : .permission = "groups-read",
999 : .handler = &TMH_private_get_groups,
1000 : },
1001 : {
1002 : .url_prefix = "/groups",
1003 : .method = MHD_HTTP_METHOD_POST,
1004 : .permission = "groups-write",
1005 : .handler = &TMH_private_post_groups,
1006 : },
1007 : {
1008 : .url_prefix = "/groups/",
1009 : .method = MHD_HTTP_METHOD_PATCH,
1010 : .handler = &TMH_private_patch_group,
1011 : .permission = "groups-write",
1012 : .have_id_segment = true,
1013 : },
1014 : {
1015 : .url_prefix = "/groups/",
1016 : .method = MHD_HTTP_METHOD_DELETE,
1017 : .handler = &TMH_private_delete_group,
1018 : .permission = "groups-write",
1019 : .have_id_segment = true,
1020 : },
1021 :
1022 : /* Money pots endpoints */
1023 : {
1024 : .url_prefix = "/pots",
1025 : .method = MHD_HTTP_METHOD_GET,
1026 : .handler = &TMH_private_get_pots,
1027 : .permission = "pots-read",
1028 : },
1029 : {
1030 : .url_prefix = "/pots",
1031 : .method = MHD_HTTP_METHOD_POST,
1032 : .handler = &TMH_private_post_pots,
1033 : .permission = "pots-write"
1034 : },
1035 : {
1036 : .url_prefix = "/pots/",
1037 : .method = MHD_HTTP_METHOD_GET,
1038 : .handler = &TMH_private_get_pot,
1039 : .have_id_segment = true,
1040 : .permission = "pots-read",
1041 : },
1042 : {
1043 : .url_prefix = "/pots/",
1044 : .method = MHD_HTTP_METHOD_PATCH,
1045 : .handler = &TMH_private_patch_pot,
1046 : .have_id_segment = true,
1047 : .permission = "pots-write"
1048 : },
1049 : {
1050 : .url_prefix = "/pots/",
1051 : .method = MHD_HTTP_METHOD_DELETE,
1052 : .handler = &TMH_private_delete_pot,
1053 : .have_id_segment = true,
1054 : .permission = "pots-write"
1055 : },
1056 :
1057 : /* GET /donau */
1058 : {
1059 : .url_prefix = "/donau",
1060 : .method = MHD_HTTP_METHOD_GET,
1061 : .permission = "donau-read",
1062 : .handler = &TMH_private_get_donau_instances
1063 : },
1064 : /* POST /donau */
1065 : {
1066 : .url_prefix = "/donau",
1067 : .method = MHD_HTTP_METHOD_POST,
1068 : .permission = "donau-write",
1069 : .handler = &TMH_private_post_donau_instance
1070 : },
1071 : /* DELETE /donau/$charity-id */
1072 : {
1073 : .url_prefix = "/donau/",
1074 : .method = MHD_HTTP_METHOD_DELETE,
1075 : .have_id_segment = true,
1076 : .permission = "donau-write",
1077 : .handler = &TMH_private_delete_donau_instance_ID
1078 : },
1079 : /* GET /statistics-counter/$SLUG: */
1080 : {
1081 : .url_prefix = "/statistics-counter/",
1082 : .method = MHD_HTTP_METHOD_GET,
1083 : .permission = "statistics-read",
1084 : .have_id_segment = true,
1085 : .handler = &TMH_private_get_statistics_counter_SLUG,
1086 : },
1087 : /* GET /statistics-amount/$SLUG: */
1088 : {
1089 : .url_prefix = "/statistics-amount/",
1090 : .method = MHD_HTTP_METHOD_GET,
1091 : .permission = "statistics-read",
1092 : .have_id_segment = true,
1093 : .handler = &TMH_private_get_statistics_amount_SLUG,
1094 : },
1095 : /* GET /statistics-report/transactions: */
1096 : {
1097 : .url_prefix = "/statistics-report/",
1098 : .url_suffix = "transactions",
1099 : .method = MHD_HTTP_METHOD_GET,
1100 : .permission = "statistics-read",
1101 : .handler = &TMH_private_get_statistics_report_transactions,
1102 : },
1103 : {
1104 : .url_prefix = NULL
1105 : }
1106 : };
1107 : static struct TMH_RequestHandler public_handlers[] = {
1108 : {
1109 : /* for "admin" instance, it does not even
1110 : have to exist before we give the WebUI */
1111 : .url_prefix = "/",
1112 : .method = MHD_HTTP_METHOD_GET,
1113 : .mime_type = "text/html",
1114 : .skip_instance = true,
1115 : .default_only = true,
1116 : .handler = &spa_redirect,
1117 : .response_code = MHD_HTTP_FOUND
1118 : },
1119 : {
1120 : .url_prefix = "/config",
1121 : .method = MHD_HTTP_METHOD_GET,
1122 : .skip_instance = true,
1123 : .default_only = true,
1124 : .handler = &MH_handler_config
1125 : },
1126 : {
1127 : .url_prefix = "/exchanges",
1128 : .method = MHD_HTTP_METHOD_GET,
1129 : .skip_instance = true,
1130 : .default_only = true,
1131 : .handler = &MH_handler_exchanges
1132 : },
1133 : {
1134 : /* for "normal" instance,s they must exist
1135 : before we give the WebUI */
1136 : .url_prefix = "/",
1137 : .method = MHD_HTTP_METHOD_GET,
1138 : .mime_type = "text/html",
1139 : .handler = &spa_redirect,
1140 : .response_code = MHD_HTTP_FOUND
1141 : },
1142 : {
1143 : .url_prefix = "/webui/",
1144 : .method = MHD_HTTP_METHOD_GET,
1145 : .mime_type = "text/html",
1146 : .skip_instance = true,
1147 : .have_id_segment = true,
1148 : .handler = &TMH_return_spa,
1149 : .response_code = MHD_HTTP_OK
1150 : },
1151 : {
1152 : .url_prefix = "/agpl",
1153 : .method = MHD_HTTP_METHOD_GET,
1154 : .skip_instance = true,
1155 : .handler = &TMH_MHD_handler_agpl_redirect
1156 : },
1157 : {
1158 : .url_prefix = "/agpl",
1159 : .method = MHD_HTTP_METHOD_GET,
1160 : .skip_instance = true,
1161 : .handler = &TMH_MHD_handler_agpl_redirect
1162 : },
1163 : {
1164 : .url_prefix = "/terms",
1165 : .method = MHD_HTTP_METHOD_GET,
1166 : .skip_instance = true,
1167 : .handler = &TMH_handler_terms
1168 : },
1169 : {
1170 : .url_prefix = "/privacy",
1171 : .method = MHD_HTTP_METHOD_GET,
1172 : .skip_instance = true,
1173 : .handler = &TMH_handler_privacy
1174 : },
1175 : /* Also serve the same /config per instance */
1176 : {
1177 : .url_prefix = "/config",
1178 : .method = MHD_HTTP_METHOD_GET,
1179 : .handler = &MH_handler_config
1180 : },
1181 : /* POST /orders/$ID/abort: */
1182 : {
1183 : .url_prefix = "/orders/",
1184 : .have_id_segment = true,
1185 : .url_suffix = "abort",
1186 : .method = MHD_HTTP_METHOD_POST,
1187 : .handler = &TMH_post_orders_ID_abort,
1188 : /* wallet may give us many coins to sign, allow 1 MB of upload
1189 : to set a conservative bound for sane wallets */
1190 : .max_upload = 1024 * 1024
1191 : },
1192 : /* POST /orders/$ID/claim: */
1193 : {
1194 : .url_prefix = "/orders/",
1195 : .have_id_segment = true,
1196 : .url_suffix = "claim",
1197 : .method = MHD_HTTP_METHOD_POST,
1198 : .handler = &TMH_post_orders_ID_claim,
1199 : /* the body should be pretty small, allow 1 MB of upload
1200 : to set a conservative bound for sane wallets */
1201 : .max_upload = 1024 * 1024
1202 : },
1203 : /* POST /orders/$ID/unclaim: */
1204 : {
1205 : .url_prefix = "/orders/",
1206 : .have_id_segment = true,
1207 : .url_suffix = "unclaim",
1208 : .method = MHD_HTTP_METHOD_POST,
1209 : .handler = &TMH_post_orders_ID_unclaim,
1210 : /* the body should be very small */
1211 : .max_upload = 1024
1212 : },
1213 : /* POST /orders/$ID/pay: */
1214 : {
1215 : .url_prefix = "/orders/",
1216 : .have_id_segment = true,
1217 : .url_suffix = "pay",
1218 : .method = MHD_HTTP_METHOD_POST,
1219 : .handler = &TMH_post_orders_ID_pay,
1220 : /* wallet may give us many coins to sign, allow 1 MB of upload
1221 : to set a conservative bound for sane wallets */
1222 : .max_upload = 1024 * 1024
1223 : },
1224 : /* POST /orders/$ID/paid: */
1225 : {
1226 : .url_prefix = "/orders/",
1227 : .have_id_segment = true,
1228 : .allow_deleted_instance = true,
1229 : .url_suffix = "paid",
1230 : .method = MHD_HTTP_METHOD_POST,
1231 : .handler = &TMH_post_orders_ID_paid,
1232 : /* the body should be pretty small, allow 1 MB of upload
1233 : to set a conservative bound for sane wallets */
1234 : .max_upload = 1024 * 1024
1235 : },
1236 : /* POST /orders/$ID/refund: */
1237 : {
1238 : .url_prefix = "/orders/",
1239 : .have_id_segment = true,
1240 : .allow_deleted_instance = true,
1241 : .url_suffix = "refund",
1242 : .method = MHD_HTTP_METHOD_POST,
1243 : .handler = &TMH_post_orders_ID_refund,
1244 : /* the body should be pretty small, allow 1 MB of upload
1245 : to set a conservative bound for sane wallets */
1246 : .max_upload = 1024 * 1024
1247 : },
1248 : /* GET /orders/$ID: */
1249 : {
1250 : .url_prefix = "/orders/",
1251 : .method = MHD_HTTP_METHOD_GET,
1252 : .allow_deleted_instance = true,
1253 : .have_id_segment = true,
1254 : .handler = &TMH_get_orders_ID
1255 : },
1256 : /* GET /sessions/$ID: */
1257 : {
1258 : .url_prefix = "/sessions/",
1259 : .method = MHD_HTTP_METHOD_GET,
1260 : .allow_deleted_instance = true,
1261 : .have_id_segment = true,
1262 : .handler = &TMH_get_sessions_ID
1263 : },
1264 : /* GET /static/ *: */
1265 : {
1266 : .url_prefix = "/static/",
1267 : .method = MHD_HTTP_METHOD_GET,
1268 : .have_id_segment = true,
1269 : .handler = &TMH_return_static
1270 : },
1271 : /* POST /reports/$ID/ */
1272 : {
1273 : .url_prefix = "/reports/",
1274 : .method = MHD_HTTP_METHOD_POST,
1275 : .have_id_segment = true,
1276 : .handler = &TMH_post_reports_ID,
1277 : },
1278 : /* GET /templates/$ID/: */
1279 : {
1280 : .url_prefix = "/templates/",
1281 : .method = MHD_HTTP_METHOD_GET,
1282 : .have_id_segment = true,
1283 : .handler = &TMH_get_templates_ID
1284 : },
1285 : /* GET /products/$HASH/image: */
1286 : {
1287 : .url_prefix = "/products/",
1288 : .method = MHD_HTTP_METHOD_GET,
1289 : .have_id_segment = true,
1290 : .allow_deleted_instance = true,
1291 : .url_suffix = "image",
1292 : .handler = &TMH_get_products_image
1293 : },
1294 : /* POST /templates/$ID: */
1295 : {
1296 : .url_prefix = "/templates/",
1297 : .method = MHD_HTTP_METHOD_POST,
1298 : .have_id_segment = true,
1299 : .handler = &TMH_post_using_templates_ID,
1300 : .max_upload = 1024 * 1024
1301 : },
1302 : /* POST /challenge/$ID: */
1303 : {
1304 : .url_prefix = "/challenge/",
1305 : .method = MHD_HTTP_METHOD_POST,
1306 : .have_id_segment = true,
1307 : .handler = &TMH_post_challenge_ID,
1308 : .max_upload = 1024
1309 : },
1310 : /* POST /challenge/$ID/confirm: */
1311 : {
1312 : .url_prefix = "/challenge/",
1313 : .method = MHD_HTTP_METHOD_POST,
1314 : .have_id_segment = true,
1315 : .url_suffix = "confirm",
1316 : .handler = &TMH_post_challenge_ID_confirm,
1317 : .max_upload = 1024
1318 : },
1319 : /* POST /instances */
1320 : {
1321 : .url_prefix = "/instances",
1322 : .method = MHD_HTTP_METHOD_POST,
1323 : .skip_instance = true,
1324 : .default_only = true,
1325 : .handler = &TMH_public_post_instances,
1326 : /* allow instance data of up to 8 MB, that should be plenty;
1327 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
1328 : would require further changes to the allocation logic
1329 : in the code... */
1330 : .max_upload = 1024 * 1024 * 8
1331 : },
1332 : /* POST /forgot-password: */
1333 : {
1334 : .url_prefix = "/forgot-password",
1335 : .method = MHD_HTTP_METHOD_POST,
1336 : .handler = &TMH_public_post_instances_ID_auth,
1337 : /* Body should be pretty small. */
1338 : .max_upload = 1024 * 1024
1339 : },
1340 :
1341 : {
1342 : .url_prefix = "*",
1343 : .method = MHD_HTTP_METHOD_OPTIONS,
1344 : .handler = &handle_server_options
1345 : },
1346 : {
1347 : .url_prefix = NULL
1348 : }
1349 : };
1350 1144 : const char *management_prefix = "/management/";
1351 1144 : const char *private_prefix = "/private/";
1352 1144 : const char *url = *urlp;
1353 : struct TMH_RequestHandler *handlers;
1354 :
1355 1144 : *is_public = false; /* ensure safe default */
1356 1144 : if ( (0 == strncmp (url,
1357 : management_prefix,
1358 : strlen (management_prefix))) )
1359 : {
1360 68 : handlers = management_handlers;
1361 68 : *urlp = url + strlen (management_prefix) - 1;
1362 : }
1363 1076 : else if ( (0 == strncmp (url,
1364 : private_prefix,
1365 335 : strlen (private_prefix))) ||
1366 335 : (0 == strcmp (url,
1367 : "/private")) )
1368 : {
1369 756 : handlers = private_handlers;
1370 1512 : if (0 == strcmp (url,
1371 : "/private"))
1372 15 : *urlp = "/";
1373 : else
1374 741 : *urlp = url + strlen (private_prefix) - 1;
1375 : }
1376 : else
1377 : {
1378 320 : handlers = public_handlers;
1379 320 : *is_public = true;
1380 : }
1381 1144 : return handlers;
1382 : }
1383 :
1384 :
1385 : /**
1386 : * Checks if the @a rh matches the given (parsed) URL.
1387 : *
1388 : * @param rh handler to compare against
1389 : * @param url the main URL (without "/private/" prefix, if any)
1390 : * @param prefix_strlen length of the prefix, i.e. 8 for '/orders/' or 7 for '/config'
1391 : * @param infix_url infix text, i.e. "$ORDER_ID".
1392 : * @param infix_strlen length of the string in @a infix_url
1393 : * @param suffix_url suffix, i.e. "/refund", including the "/"
1394 : * @param suffix_strlen number of characters in @a suffix_url
1395 : * @return true if @a rh matches this request
1396 : */
1397 : static bool
1398 27974 : prefix_match (const struct TMH_RequestHandler *rh,
1399 : const char *url,
1400 : size_t prefix_strlen,
1401 : const char *infix_url,
1402 : size_t infix_strlen,
1403 : const char *suffix_url,
1404 : size_t suffix_strlen)
1405 : {
1406 27974 : if ( (prefix_strlen != strlen (rh->url_prefix)) ||
1407 4136 : (0 != memcmp (url,
1408 4136 : rh->url_prefix,
1409 : prefix_strlen)) )
1410 25591 : return false;
1411 2383 : if (! rh->have_id_segment)
1412 : {
1413 : /* Require /$PREFIX/$SUFFIX or /$PREFIX */
1414 673 : if (NULL != suffix_url)
1415 0 : return false; /* too many segments to match */
1416 673 : if ( (NULL == infix_url) /* either or */
1417 673 : ^ (NULL == rh->url_suffix) )
1418 0 : return false; /* suffix existence mismatch */
1419 : /* If /$PREFIX/$SUFFIX, check $SUFFIX matches */
1420 673 : if ( (NULL != infix_url) &&
1421 1 : ( (infix_strlen != strlen (rh->url_suffix)) ||
1422 1 : (0 != memcmp (infix_url,
1423 1 : rh->url_suffix,
1424 : infix_strlen)) ) )
1425 0 : return false; /* cannot use infix as suffix: content mismatch */
1426 : }
1427 : else
1428 : {
1429 : /* Require /$PREFIX/$ID or /$PREFIX/$ID/$SUFFIX */
1430 1710 : if (NULL == infix_url)
1431 0 : return false; /* infix existence mismatch */
1432 1710 : if ( ( (NULL == suffix_url)
1433 1710 : ^ (NULL == rh->url_suffix) ) )
1434 446 : return false; /* suffix existence mismatch */
1435 1264 : if ( (NULL != suffix_url) &&
1436 680 : ( (suffix_strlen != strlen (rh->url_suffix)) ||
1437 389 : (0 != memcmp (suffix_url,
1438 389 : rh->url_suffix,
1439 : suffix_strlen)) ) )
1440 398 : return false; /* suffix content mismatch */
1441 : }
1442 1539 : return true;
1443 : }
1444 :
1445 :
1446 : /**
1447 : * Identify the handler of the request from the @a url and @a method
1448 : *
1449 : * @param[in,out] hc handler context to update with applicable handler
1450 : * @param handlers array of handlers to consider
1451 : * @param url URL to match against the handlers
1452 : * @param method HTTP access method to consider
1453 : * @param use_admin set to true if we are using the admin instance
1454 : * @return #GNUNET_OK on success,
1455 : * #GNUNET_NO if an error was queued (return #MHD_YES)
1456 : * #GNUNET_SYSERR to close the connection (return #MHD_NO)
1457 : */
1458 : static enum GNUNET_GenericReturnValue
1459 1144 : identify_handler (struct TMH_HandlerContext *hc,
1460 : const struct TMH_RequestHandler *handlers,
1461 : const char *url,
1462 : const char *method,
1463 : bool use_admin)
1464 : {
1465 : size_t prefix_strlen; /* i.e. 8 for "/orders/", or 7 for "/config" */
1466 1144 : const char *infix_url = NULL; /* i.e. "$ORDER_ID", no '/'-es */
1467 1144 : size_t infix_strlen = 0; /* number of characters in infix_url */
1468 1144 : const char *suffix_url = NULL; /* i.e. "refund", excludes '/' at the beginning */
1469 1144 : size_t suffix_strlen = 0; /* number of characters in suffix_url */
1470 :
1471 1144 : if (0 == strcasecmp (method,
1472 : MHD_HTTP_METHOD_HEAD))
1473 0 : method = MHD_HTTP_METHOD_GET; /* MHD will deal with the rest */
1474 1144 : if (0 == strcmp (url,
1475 : ""))
1476 0 : url = "/"; /* code below does not like empty string */
1477 :
1478 : /* parse the URL into the three different components */
1479 : {
1480 : const char *slash;
1481 :
1482 1144 : slash = strchr (&url[1], '/');
1483 1144 : if (NULL == slash)
1484 : {
1485 : /* the prefix was everything */
1486 492 : prefix_strlen = strlen (url);
1487 : }
1488 : else
1489 : {
1490 652 : prefix_strlen = slash - url + 1; /* includes both '/'-es if present! */
1491 652 : infix_url = slash + 1;
1492 652 : slash = strchr (infix_url, '/');
1493 652 : if (NULL == slash)
1494 : {
1495 : /* the infix was the rest */
1496 370 : infix_strlen = strlen (infix_url);
1497 : }
1498 : else
1499 : {
1500 282 : infix_strlen = slash - infix_url; /* excludes both '/'-es */
1501 282 : suffix_url = slash + 1; /* skip the '/' */
1502 282 : suffix_strlen = strlen (suffix_url);
1503 : }
1504 : /* free any previously set infix in case the request is being
1505 : re-dispatched (e.g. via POST /reports/$REPORT_ID), otherwise
1506 : the earlier infix would be leaked */
1507 652 : GNUNET_free (hc->infix);
1508 652 : hc->infix = GNUNET_strndup (infix_url,
1509 : infix_strlen);
1510 : }
1511 : }
1512 :
1513 : /* find matching handler */
1514 : {
1515 1144 : bool url_found = false;
1516 :
1517 28016 : for (unsigned int i = 0; NULL != handlers[i].url_prefix; i++)
1518 : {
1519 28016 : const struct TMH_RequestHandler *rh = &handlers[i];
1520 :
1521 28016 : if (rh->default_only && (! use_admin))
1522 42 : continue;
1523 27974 : if (! prefix_match (rh,
1524 : url,
1525 : prefix_strlen,
1526 : infix_url,
1527 : infix_strlen,
1528 : suffix_url,
1529 : suffix_strlen))
1530 26435 : continue;
1531 1539 : url_found = true;
1532 1539 : if (0 == strcasecmp (method,
1533 : MHD_HTTP_METHOD_OPTIONS))
1534 : {
1535 : return (MHD_YES ==
1536 1 : TALER_MHD_reply_cors_preflight (hc->connection))
1537 : ? GNUNET_NO
1538 1 : : GNUNET_SYSERR;
1539 : }
1540 1538 : if ( (rh->method != NULL) &&
1541 1538 : (0 != strcasecmp (method,
1542 1538 : rh->method)) )
1543 395 : continue;
1544 1143 : hc->rh = rh;
1545 1143 : break;
1546 : }
1547 : /* Handle HTTP 405: METHOD NOT ALLOWED case */
1548 1143 : if ( (NULL == hc->rh) &&
1549 : (url_found) )
1550 : {
1551 : struct MHD_Response *reply;
1552 : enum MHD_Result ret;
1553 0 : char *allowed = NULL;
1554 :
1555 0 : GNUNET_break_op (0);
1556 : /* compute 'Allowed:' header (required by HTTP spec for 405 replies) */
1557 0 : for (unsigned int i = 0; NULL != handlers[i].url_prefix; i++)
1558 : {
1559 0 : const struct TMH_RequestHandler *rh = &handlers[i];
1560 :
1561 0 : if (rh->default_only && (! use_admin))
1562 0 : continue;
1563 0 : if (! prefix_match (rh,
1564 : url,
1565 : prefix_strlen,
1566 : infix_url,
1567 : infix_strlen,
1568 : suffix_url,
1569 : suffix_strlen))
1570 0 : continue;
1571 0 : if (NULL == allowed)
1572 : {
1573 0 : allowed = GNUNET_strdup (rh->method);
1574 : }
1575 : else
1576 : {
1577 : char *tmp;
1578 :
1579 0 : GNUNET_asprintf (&tmp,
1580 : "%s, %s",
1581 : allowed,
1582 0 : rh->method);
1583 0 : GNUNET_free (allowed);
1584 0 : allowed = tmp;
1585 : }
1586 0 : if (0 == strcasecmp (rh->method,
1587 : MHD_HTTP_METHOD_GET))
1588 : {
1589 : char *tmp;
1590 :
1591 0 : GNUNET_asprintf (&tmp,
1592 : "%s, %s",
1593 : allowed,
1594 : MHD_HTTP_METHOD_HEAD);
1595 0 : GNUNET_free (allowed);
1596 0 : allowed = tmp;
1597 : }
1598 : }
1599 0 : reply = TALER_MHD_make_error (TALER_EC_GENERIC_METHOD_INVALID,
1600 : method);
1601 0 : GNUNET_break (MHD_YES ==
1602 : MHD_add_response_header (reply,
1603 : MHD_HTTP_HEADER_ALLOW,
1604 : allowed));
1605 0 : GNUNET_free (allowed);
1606 0 : ret = MHD_queue_response (hc->connection,
1607 : MHD_HTTP_METHOD_NOT_ALLOWED,
1608 : reply);
1609 0 : MHD_destroy_response (reply);
1610 : return (MHD_YES == ret)
1611 : ? GNUNET_NO
1612 0 : : GNUNET_SYSERR;
1613 : }
1614 1143 : if (NULL == hc->rh)
1615 : {
1616 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1617 : "Endpoint `%s' not known\n",
1618 : hc->url);
1619 : return (MHD_YES ==
1620 0 : TALER_MHD_reply_with_error (hc->connection,
1621 : MHD_HTTP_NOT_FOUND,
1622 : TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
1623 : hc->url))
1624 : ? GNUNET_NO
1625 0 : : GNUNET_SYSERR;
1626 : }
1627 : }
1628 1143 : return GNUNET_OK;
1629 : }
1630 :
1631 :
1632 : enum GNUNET_GenericReturnValue
1633 1144 : TMH_dispatch_request (struct TMH_HandlerContext *hc,
1634 : const char *url,
1635 : const char *method,
1636 : bool use_admin,
1637 : bool *is_public)
1638 : {
1639 : const struct TMH_RequestHandler *handlers;
1640 :
1641 1144 : *is_public = false;
1642 1144 : handlers = determine_handler_group (&url,
1643 : is_public);
1644 1144 : return identify_handler (hc,
1645 : handlers,
1646 : url,
1647 : method,
1648 : use_admin);
1649 : }
|