Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2019-2024 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU 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 payto.c
18 : * @brief Common utility functions for dealing with payto://-URIs
19 : * @author Florian Dold
20 : */
21 : #include "platform.h" /* UNNECESSARY? */
22 : #include "taler/taler_util.h"
23 :
24 :
25 : /**
26 : * Prefix of PAYTO URLs.
27 : */
28 : #define PAYTO "payto://"
29 :
30 :
31 : int
32 25 : TALER_full_payto_cmp (const struct TALER_FullPayto a,
33 : const struct TALER_FullPayto b)
34 : {
35 25 : if ( (NULL == a.full_payto) &&
36 0 : (NULL == b.full_payto) )
37 0 : return 0;
38 25 : if (NULL == a.full_payto)
39 0 : return -1;
40 25 : if (NULL == b.full_payto)
41 0 : return 1;
42 25 : return strcmp (a.full_payto,
43 25 : b.full_payto);
44 : }
45 :
46 :
47 : bool
48 356 : TALER_payto_is_wallet (const char *payto_uri)
49 : {
50 : return
51 356 : (0 == strncasecmp (payto_uri,
52 : "payto://taler-reserve/",
53 712 : strlen ("payto://taler-reserve/"))) ||
54 356 : (0 == strncasecmp (payto_uri,
55 : "payto://taler-reserve-http/",
56 : strlen ("payto://taler-reserve-http/")));
57 : }
58 :
59 :
60 : int
61 4 : TALER_normalized_payto_cmp (const struct TALER_NormalizedPayto a,
62 : const struct TALER_NormalizedPayto b)
63 : {
64 4 : if ( (NULL == a.normalized_payto) &&
65 0 : (NULL == b.normalized_payto) )
66 0 : return 0;
67 4 : if (NULL == a.normalized_payto)
68 0 : return -1;
69 4 : if (NULL == b.normalized_payto)
70 0 : return 1;
71 4 : return strcmp (a.normalized_payto,
72 4 : b.normalized_payto);
73 : }
74 :
75 :
76 : void
77 422 : TALER_full_payto_normalize_and_hash (const struct TALER_FullPayto in,
78 : struct TALER_NormalizedPaytoHashP *out)
79 : {
80 : struct TALER_NormalizedPayto normalized_payto_uri;
81 :
82 : normalized_payto_uri
83 422 : = TALER_payto_normalize (in);
84 422 : if (NULL == normalized_payto_uri.normalized_payto)
85 : {
86 : /* Callers must have validated @a in; never crash on a URI that
87 : slipped through. */
88 0 : GNUNET_break (0);
89 0 : memset (out,
90 : 0,
91 : sizeof (*out));
92 0 : return;
93 : }
94 422 : TALER_normalized_payto_hash (normalized_payto_uri,
95 : out);
96 422 : GNUNET_free (normalized_payto_uri.normalized_payto);
97 : }
98 :
99 :
100 : /**
101 : * Compare two full payto URIs for equality in their normalized form.
102 : *
103 : * @param a a full payto URI, NULL is permitted
104 : * @param b a full payto URI, NULL is permitted
105 : * @return 0 if both are equal, otherwise -1 or 1
106 : */
107 : int
108 4 : TALER_full_payto_normalize_and_cmp (const struct TALER_FullPayto a,
109 : const struct TALER_FullPayto b)
110 : {
111 : struct TALER_NormalizedPayto an
112 4 : = TALER_payto_normalize (a);
113 : struct TALER_NormalizedPayto bn
114 4 : = TALER_payto_normalize (b);
115 : int ret;
116 :
117 4 : ret = TALER_normalized_payto_cmp (an,
118 : bn);
119 4 : GNUNET_free (an.normalized_payto);
120 4 : GNUNET_free (bn.normalized_payto);
121 4 : return ret;
122 : }
123 :
124 :
125 : /**
126 : * Extract the value under @a key from the URI parameters.
127 : *
128 : * @param fpayto_uri the full payto URL to parse
129 : * @param search_key key to look for, including "="
130 : * @return NULL if the @a key parameter is not found.
131 : * The caller should free the returned value.
132 : */
133 : static char *
134 1906 : payto_get_key (const struct TALER_FullPayto fpayto_uri,
135 : const char *search_key)
136 : {
137 1906 : const char *payto_uri = fpayto_uri.full_payto;
138 : const char *key;
139 : const char *value_start;
140 : const char *value_end;
141 :
142 1906 : key = strchr (payto_uri,
143 : (unsigned char) '?');
144 1906 : if (NULL == key)
145 1 : return NULL;
146 :
147 : do {
148 1905 : if (0 == strncasecmp (++key,
149 : search_key,
150 : strlen (search_key)))
151 : {
152 1905 : value_start = strchr (key,
153 : (unsigned char) '=');
154 1905 : if (NULL == value_start)
155 0 : return NULL;
156 1905 : value_end = strchrnul (value_start,
157 : (unsigned char) '&');
158 :
159 1905 : return GNUNET_strndup (value_start + 1,
160 : value_end - value_start - 1);
161 : }
162 0 : } while ( (key = strchr (key,
163 : (unsigned char) '&')) );
164 0 : return NULL;
165 : }
166 :
167 :
168 : char *
169 2 : TALER_payto_get_subject (const struct TALER_FullPayto payto_uri)
170 : {
171 2 : return payto_get_key (payto_uri,
172 : "subject=");
173 : }
174 :
175 :
176 : char *
177 990 : TALER_payto_get_method (const char *payto_uri)
178 : {
179 : const char *start;
180 : const char *end;
181 :
182 990 : if (0 != strncasecmp (payto_uri,
183 : PAYTO,
184 : strlen (PAYTO)))
185 0 : return NULL;
186 990 : start = &payto_uri[strlen (PAYTO)];
187 990 : end = strchr (start,
188 : (unsigned char) '/');
189 990 : if (NULL == end)
190 0 : return NULL;
191 990 : return GNUNET_strndup (start,
192 : end - start);
193 : }
194 :
195 :
196 : char *
197 335 : TALER_xtalerbank_account_from_payto (const struct TALER_FullPayto payto)
198 : {
199 : const char *host;
200 : const char *beg;
201 : const char *nxt;
202 : const char *end;
203 :
204 335 : if (0 != strncasecmp (payto.full_payto,
205 : PAYTO "x-taler-bank/",
206 : strlen (PAYTO "x-taler-bank/")))
207 : {
208 0 : GNUNET_break_op (0);
209 0 : return NULL;
210 : }
211 335 : host = &payto.full_payto[strlen (PAYTO "x-taler-bank/")];
212 335 : beg = strchr (host,
213 : '/');
214 335 : if (NULL == beg)
215 : {
216 0 : GNUNET_break_op (0);
217 0 : return NULL;
218 : }
219 335 : beg++; /* now points to $ACCOUNT or $PATH */
220 335 : nxt = strchr (beg,
221 : '/');
222 335 : end = strchr (beg,
223 : '?');
224 335 : if (NULL == end)
225 0 : end = &beg[strlen (beg)];
226 337 : while ( (NULL != nxt) &&
227 3 : (end - nxt > 0) )
228 : {
229 2 : beg = nxt + 1;
230 2 : nxt = strchr (beg,
231 : '/');
232 : }
233 335 : return GNUNET_strndup (beg,
234 : end - beg);
235 : }
236 :
237 :
238 : /**
239 : * Validate payto://iban/ account URL (only account information,
240 : * wire subject and amount are ignored).
241 : *
242 : * @param payto_uri payto URL to parse
243 : * @return NULL on success, otherwise an error message
244 : * to be freed by the caller
245 : */
246 : static char *
247 1916 : validate_payto_iban (const char *payto_uri)
248 : {
249 1916 : size_t slen = strlen (payto_uri);
250 : const char *iban;
251 : const char *q;
252 : char *result;
253 : char *err;
254 :
255 : #define IBAN_PREFIX "payto://iban/"
256 1916 : if (0 != strncasecmp (payto_uri,
257 : IBAN_PREFIX,
258 : strlen (IBAN_PREFIX)))
259 1916 : return NULL; /* not an IBAN */
260 0 : q = memchr (payto_uri,
261 : '?',
262 : slen);
263 : /* RFC 8905, Section 7.3: the path is either "$IBAN" or "$BIC/$IBAN".
264 : Reject anything else here, so that normalize_payto_iban() -- which
265 : enforces the same rule by returning NULL -- can never be handed a
266 : URI that passed validation. */
267 : {
268 0 : unsigned int sc = 0;
269 0 : size_t plen = (NULL == q)
270 : ? slen
271 0 : : (size_t) (q - payto_uri);
272 :
273 0 : for (size_t i = 0; i < plen; i++)
274 0 : if ('/' == payto_uri[i])
275 0 : sc++;
276 0 : if ( (sc < 3) ||
277 : (sc > 4) )
278 0 : return GNUNET_strdup (
279 : "'iban' payto:// URI must have one or two path components");
280 : }
281 : /* Find the last '/' that is part of the path, i.e. before any '?'
282 : query part ('/' is a legal character in a query value and must
283 : not be mistaken for the path separator). */
284 : {
285 : const char *slash;
286 :
287 0 : slash = memrchr (payto_uri,
288 : '/',
289 : (NULL == q)
290 : ? slen
291 0 : : q - payto_uri);
292 0 : GNUNET_assert (NULL != slash); /* prefix guarantees a '/' */
293 0 : iban = slash + 1;
294 : }
295 : #undef IBAN_PREFIX
296 0 : if (NULL != q)
297 : {
298 0 : result = GNUNET_strndup (iban,
299 : q - iban);
300 : }
301 : else
302 : {
303 0 : result = GNUNET_strdup (iban);
304 : }
305 0 : if (NULL !=
306 0 : (err = TALER_iban_validate (result)))
307 : {
308 0 : GNUNET_free (result);
309 0 : return err;
310 : }
311 0 : GNUNET_free (result);
312 0 : return NULL;
313 : }
314 :
315 :
316 : /**
317 : * Validate payto://x-taler-bank/ account URL (only account information,
318 : * wire subject and amount are ignored).
319 : *
320 : * @param payto_uri payto URL to parse
321 : * @return NULL on success, otherwise an error message
322 : * to be freed by the caller
323 : */
324 : static char *
325 1916 : validate_payto_xtalerbank (const char *payto_uri)
326 : {
327 : const char *user;
328 : const char *nxt;
329 : const char *beg;
330 : const char *end;
331 : const char *host;
332 : bool dot_ok;
333 : bool post_colon;
334 : bool port_ok;
335 :
336 : #define XTALERBANK_PREFIX PAYTO "x-taler-bank/"
337 1916 : if (0 != strncasecmp (payto_uri,
338 : XTALERBANK_PREFIX,
339 : strlen (XTALERBANK_PREFIX)))
340 6 : return NULL; /* not an x-taler-bank URI */
341 1910 : host = &payto_uri[strlen (XTALERBANK_PREFIX)];
342 : #undef XTALERBANK_PREFIX
343 1910 : beg = strchr (host,
344 : '/');
345 1910 : if (NULL == beg)
346 : {
347 0 : return GNUNET_strdup ("account name missing");
348 : }
349 1910 : beg++; /* now points to $ACCOUNT or $PATH */
350 1910 : nxt = strchr (beg,
351 : '/');
352 1910 : end = strchr (beg,
353 : '?');
354 1910 : if (NULL == end)
355 : {
356 1 : return GNUNET_strdup ("'receiver-name' parameter missing");
357 : }
358 1916 : while ( (NULL != nxt) &&
359 8 : (end - nxt > 0) )
360 : {
361 7 : beg = nxt + 1;
362 7 : nxt = strchr (beg,
363 : '/');
364 : }
365 1909 : user = beg;
366 1909 : if (user == host + 1)
367 : {
368 0 : return GNUNET_strdup ("domain name missing");
369 : }
370 1909 : if ('-' == host[0])
371 1 : return GNUNET_strdup ("invalid character '-' at start of domain name");
372 1908 : dot_ok = false;
373 1908 : post_colon = false;
374 1908 : port_ok = false;
375 19080 : while (host != user)
376 : {
377 19080 : char c = host[0];
378 :
379 19080 : if ('/' == c)
380 : {
381 : /* path started, do not care about characters
382 : in the path */
383 1905 : break;
384 : }
385 17175 : if (':' == c)
386 : {
387 4 : post_colon = true;
388 4 : host++;
389 4 : continue;
390 : }
391 17171 : if (post_colon)
392 : {
393 10 : if (! ( ('0' <= c) && ('9' >= c) ) )
394 : {
395 : char *err;
396 :
397 1 : GNUNET_asprintf (&err,
398 : "invalid character '%c' in port",
399 : c);
400 1 : return err;
401 : }
402 9 : port_ok = true;
403 : }
404 : else
405 : {
406 17161 : if ('.' == c)
407 : {
408 4 : if (! dot_ok)
409 2 : return GNUNET_strdup ("invalid domain name (misplaced '.')");
410 2 : dot_ok = false;
411 : }
412 : else
413 : {
414 17157 : if (! ( ('-' == c) ||
415 17156 : ('_' == c) ||
416 17156 : ( ('0' <= c) && ('9' >= c) ) ||
417 17156 : ( ('a' <= c) && ('z' >= c) ) ||
418 0 : ( ('A' <= c) && ('Z' >= c) ) ) )
419 : {
420 : char *err;
421 :
422 0 : GNUNET_asprintf (&err,
423 : "invalid character '%c' in domain name",
424 : c);
425 0 : return err;
426 : }
427 17157 : dot_ok = true;
428 : }
429 : }
430 17168 : host++;
431 : }
432 1905 : if (post_colon && (! port_ok) )
433 : {
434 1 : return GNUNET_strdup ("port missing after ':'");
435 : }
436 1904 : return NULL;
437 : }
438 :
439 :
440 : /**
441 : * Generic validation of a payto:// URI. Checks the prefix
442 : * and character set.
443 : *
444 : * @param payto_uri URI to validate
445 : * @return NULL on success, otherwise an error message
446 : */
447 : static char *
448 1916 : payto_validate (const char *payto_uri)
449 : {
450 : char *ret;
451 : const char *start;
452 : const char *end;
453 :
454 1916 : if (0 != strncasecmp (payto_uri,
455 : PAYTO,
456 : strlen (PAYTO)))
457 0 : return GNUNET_strdup ("invalid prefix");
458 98789 : for (unsigned int i = 0; '\0' != payto_uri[i]; i++)
459 : {
460 : /* This is more strict than RFC 8905, alas we do not need to support messages/instructions/etc.,
461 : and it is generally better to start with a narrow whitelist; we can be more permissive later ...*/
462 : #define ALLOWED_CHARACTERS \
463 : "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/:$&?!-_.,;=*+%~@()[]"
464 96873 : if (NULL == strchr (ALLOWED_CHARACTERS,
465 96873 : (int) payto_uri[i]))
466 : {
467 0 : GNUNET_asprintf (&ret,
468 : "Encountered invalid character `%c' at offset %u in payto URI `%s'",
469 0 : payto_uri[i],
470 : i,
471 : payto_uri);
472 0 : return ret;
473 : }
474 : #undef ALLOWED_CHARACTERS
475 : }
476 :
477 1916 : start = &payto_uri[strlen (PAYTO)];
478 1916 : end = strchr (start,
479 : (unsigned char) '/');
480 1916 : if (NULL == end)
481 0 : return GNUNET_strdup ("missing '/' in payload");
482 :
483 1916 : if (NULL != (ret = validate_payto_iban (payto_uri)))
484 0 : return ret; /* got a definitive answer */
485 1916 : if (NULL != (ret = validate_payto_xtalerbank (payto_uri)))
486 6 : return ret; /* got a definitive answer */
487 :
488 : /* Insert validation calls for other bank account validation methods here! */
489 :
490 1910 : return NULL;
491 : }
492 :
493 :
494 : char *
495 6 : TALER_normalized_payto_validate (const struct TALER_NormalizedPayto npayto_uri)
496 : {
497 6 : const char *payto_uri = npayto_uri.normalized_payto;
498 : char *ret;
499 :
500 6 : ret = payto_validate (payto_uri);
501 6 : if (NULL != ret)
502 0 : return ret;
503 6 : return NULL;
504 : }
505 :
506 :
507 : char *
508 1910 : TALER_payto_validate (const struct TALER_FullPayto fpayto_uri)
509 : {
510 1910 : const char *payto_uri = fpayto_uri.full_payto;
511 : char *ret;
512 :
513 1910 : ret = payto_validate (payto_uri);
514 1910 : if (NULL != ret)
515 6 : return ret;
516 : {
517 : char *target;
518 :
519 1904 : target = payto_get_key (fpayto_uri,
520 : "receiver-name=");
521 1904 : if (NULL == target)
522 0 : return GNUNET_strdup ("'receiver-name' parameter missing");
523 1904 : GNUNET_free (target);
524 : }
525 :
526 1904 : return NULL;
527 : }
528 :
529 :
530 : char *
531 0 : TALER_payto_get_receiver_name (const struct TALER_FullPayto fpayto)
532 : {
533 : char *err;
534 :
535 0 : err = TALER_payto_validate (fpayto);
536 0 : if (NULL != err)
537 : {
538 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
539 : "Invalid payto://-URI `%s': %s\n",
540 : fpayto.full_payto,
541 : err);
542 0 : GNUNET_free (err);
543 0 : return NULL;
544 : }
545 0 : return payto_get_key (fpayto,
546 : "receiver-name=");
547 : }
548 :
549 :
550 : /**
551 : * Normalize "payto://x-taler-bank/$HOSTNAME/[$PATH/]$USERNAME"
552 : * URI in @a input.
553 : *
554 : * Converts to lower-case, except for [$PATH/]$USERNAME which
555 : * is case-sensitive.
556 : *
557 : * @param len number of bytes in @a input
558 : * @param input input URL
559 : * @return NULL on error, otherwise 0-terminated canonicalized URI.
560 : */
561 : static char *
562 469 : normalize_payto_x_taler_bank (size_t len,
563 : const char input[static len])
564 469 : {
565 469 : char *res = GNUNET_malloc (len + 1);
566 469 : unsigned int sc = 0;
567 :
568 16139 : for (unsigned int i = 0; i<len; i++)
569 : {
570 15670 : char c = input[i];
571 :
572 15670 : if ('/' == c)
573 1876 : sc++;
574 15670 : if (sc < 4)
575 14070 : res[i] = (char) tolower ((int) c);
576 : else
577 1600 : res[i] = c;
578 : }
579 469 : return res;
580 : }
581 :
582 :
583 : /**
584 : * Normalize "payto://iban[/$BIC]/$IBAN"
585 : * URI in @a input.
586 : *
587 : * Removes $BIC (if present) and converts $IBAN to upper-case and prefix to
588 : * lower-case.
589 : *
590 : * @param len number of bytes in @a input
591 : * @param input input URL
592 : * @return NULL on error, otherwise 0-terminated canonicalized URI.
593 : */
594 : static char *
595 0 : normalize_payto_iban (size_t len,
596 : const char input[static len])
597 0 : {
598 : char *res;
599 0 : size_t pos = 0;
600 0 : unsigned int sc = 0;
601 : bool have_bic;
602 :
603 0 : for (unsigned int i = 0; i<len; i++)
604 0 : if ('/' == input[i])
605 0 : sc++;
606 0 : if ( (sc > 4) ||
607 : (sc < 3) )
608 : {
609 0 : GNUNET_break (0);
610 0 : return NULL;
611 : }
612 0 : have_bic = (4 == sc);
613 0 : res = GNUNET_malloc (len + 1);
614 0 : sc = 0;
615 0 : for (unsigned int i = 0; i<len; i++)
616 : {
617 0 : char c = input[i];
618 :
619 0 : if ('/' == c)
620 0 : sc++;
621 0 : switch (sc)
622 : {
623 0 : case 0: /* payto: */
624 : case 1: /* / */
625 : case 2: /* /iban */
626 0 : res[pos++] = (char) tolower ((int) c);
627 0 : break;
628 0 : case 3: /* /$BIC or /$IBAN */
629 0 : if (have_bic)
630 0 : continue;
631 0 : res[pos++] = (char) toupper ((int) c);
632 0 : break;
633 0 : case 4: /* /$IBAN */
634 0 : res[pos++] = (char) toupper ((int) c);
635 0 : break;
636 : }
637 : }
638 0 : GNUNET_assert (pos <= len);
639 0 : return res;
640 : }
641 :
642 :
643 : /**
644 : * Normalize "payto://upi/$EMAIL"
645 : * URI in @a input.
646 : *
647 : * Converts to lower-case.
648 : *
649 : * @param len number of bytes in @a input
650 : * @param input input URL
651 : * @return NULL on error, otherwise 0-terminated canonicalized URI.
652 : */
653 : static char *
654 0 : normalize_payto_upi (size_t len,
655 : const char input[static len])
656 0 : {
657 0 : char *res = GNUNET_malloc (len + 1);
658 :
659 0 : for (unsigned int i = 0; i<len; i++)
660 : {
661 0 : char c = input[i];
662 :
663 0 : res[i] = (char) tolower ((int) c);
664 : }
665 0 : return res;
666 : }
667 :
668 :
669 : /**
670 : * Normalize "payto://bitcoin/$ADDRESS"
671 : * URI in @a input.
672 : *
673 : * Converts to lower-case, except for $ADDRESS which
674 : * is case-sensitive.
675 : *
676 : * @param len number of bytes in @a input
677 : * @param input input URL
678 : * @return NULL on error, otherwise 0-terminated canonicalized URI.
679 : */
680 : static char *
681 0 : normalize_payto_bitcoin (size_t len,
682 : const char input[static len])
683 0 : {
684 0 : char *res = GNUNET_malloc (len + 1);
685 0 : unsigned int sc = 0;
686 :
687 0 : for (unsigned int i = 0; i<len; i++)
688 : {
689 0 : char c = input[i];
690 :
691 0 : if ('/' == c)
692 0 : sc++;
693 0 : if (sc < 3)
694 0 : res[i] = (char) tolower ((int) c);
695 : else
696 0 : res[i] = c;
697 : }
698 0 : return res;
699 : }
700 :
701 :
702 : /**
703 : * Normalize "payto://ilp/$NAME"
704 : * URI in @a input.
705 : *
706 : * Converts to lower-case.
707 : *
708 : * @param len number of bytes in @a input
709 : * @param input input URL
710 : * @return NULL on error, otherwise 0-terminated canonicalized URI.
711 : */
712 : static char *
713 0 : normalize_payto_ilp (size_t len,
714 : const char input[static len])
715 0 : {
716 0 : char *res = GNUNET_malloc (len + 1);
717 :
718 0 : for (unsigned int i = 0; i<len; i++)
719 : {
720 0 : char c = input[i];
721 :
722 0 : res[i] = (char) tolower ((int) c);
723 : }
724 0 : return res;
725 : }
726 :
727 :
728 : struct TALER_NormalizedPayto
729 469 : TALER_payto_normalize (const struct TALER_FullPayto input)
730 : {
731 469 : struct TALER_NormalizedPayto npto = {
732 : .normalized_payto = NULL
733 : };
734 : char *method;
735 : const char *end;
736 : char *ret;
737 :
738 : {
739 : char *err;
740 :
741 469 : err = TALER_payto_validate (input);
742 469 : if (NULL != err)
743 : {
744 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
745 : "Malformed payto://-URI `%s': %s\n",
746 : input.full_payto,
747 : err);
748 0 : GNUNET_free (err);
749 0 : return npto;
750 : }
751 : }
752 469 : method = TALER_payto_get_method (input.full_payto);
753 469 : if (NULL == method)
754 : {
755 0 : GNUNET_break (0);
756 0 : return npto;
757 : }
758 469 : end = strchr (input.full_payto,
759 : '?');
760 469 : if (NULL == end)
761 0 : end = &input.full_payto[strlen (input.full_payto)];
762 469 : if (0 == strcasecmp (method,
763 : "x-taler-bank"))
764 469 : ret = normalize_payto_x_taler_bank (end - input.full_payto,
765 469 : input.full_payto);
766 0 : else if (0 == strcasecmp (method,
767 : "iban"))
768 0 : ret = normalize_payto_iban (end - input.full_payto,
769 0 : input.full_payto);
770 0 : else if (0 == strcasecmp (method,
771 : "upi"))
772 0 : ret = normalize_payto_upi (end - input.full_payto,
773 0 : input.full_payto);
774 0 : else if (0 == strcasecmp (method,
775 : "bitcoin"))
776 0 : ret = normalize_payto_bitcoin (end - input.full_payto,
777 0 : input.full_payto);
778 0 : else if (0 == strcasecmp (method,
779 : "ilp"))
780 0 : ret = normalize_payto_ilp (end - input.full_payto,
781 0 : input.full_payto);
782 : else
783 0 : ret = GNUNET_strndup (input.full_payto,
784 : end - input.full_payto);
785 469 : GNUNET_free (method);
786 469 : npto.normalized_payto = ret;
787 469 : return npto;
788 : }
789 :
790 :
791 : void
792 584 : TALER_normalized_payto_hash (const struct TALER_NormalizedPayto npayto,
793 : struct TALER_NormalizedPaytoHashP *h_npayto)
794 : {
795 : struct GNUNET_HashCode sha512;
796 :
797 : GNUNET_static_assert (sizeof (sha512) > sizeof (*h_npayto));
798 584 : GNUNET_CRYPTO_hash (npayto.normalized_payto,
799 584 : strlen (npayto.normalized_payto) + 1,
800 : &sha512);
801 : /* truncate */
802 584 : GNUNET_memcpy (h_npayto,
803 : &sha512,
804 : sizeof (*h_npayto));
805 584 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
806 : "Normalized hash of normalized payto `%s' is %16s\n",
807 : npayto.normalized_payto,
808 : GNUNET_h2s_full (&sha512));
809 584 : }
810 :
811 :
812 : void
813 568 : TALER_full_payto_hash (const struct TALER_FullPayto fpayto,
814 : struct TALER_FullPaytoHashP *h_fpayto)
815 : {
816 : struct GNUNET_HashCode sha512;
817 :
818 : GNUNET_static_assert (sizeof (sha512) > sizeof (*h_fpayto));
819 568 : GNUNET_CRYPTO_hash (fpayto.full_payto,
820 568 : strlen (fpayto.full_payto) + 1,
821 : &sha512);
822 : /* truncate */
823 568 : GNUNET_memcpy (h_fpayto,
824 : &sha512,
825 : sizeof (*h_fpayto));
826 568 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
827 : "Full hash of full payto `%s' is %16s\n",
828 : fpayto.full_payto,
829 : GNUNET_h2s_full (&sha512));
830 568 : }
831 :
832 :
833 : struct TALER_NormalizedPayto
834 179 : TALER_reserve_make_payto (const char *exchange_url,
835 : const struct TALER_ReservePublicKeyP *reserve_pub)
836 : {
837 179 : struct TALER_NormalizedPayto npto = {
838 : .normalized_payto = NULL
839 : };
840 : char pub_str[sizeof (*reserve_pub) * 2];
841 : char *end;
842 : bool is_http;
843 : char *reserve_url;
844 :
845 179 : end = GNUNET_STRINGS_data_to_string (
846 : reserve_pub,
847 : sizeof (*reserve_pub),
848 : pub_str,
849 : sizeof (pub_str));
850 179 : *end = '\0';
851 179 : if (0 == strncmp (exchange_url,
852 : "http://",
853 : strlen ("http://")))
854 : {
855 179 : is_http = true;
856 179 : exchange_url = &exchange_url[strlen ("http://")];
857 : }
858 0 : else if (0 == strncmp (exchange_url,
859 : "https://",
860 : strlen ("https://")))
861 : {
862 0 : is_http = false;
863 0 : exchange_url = &exchange_url[strlen ("https://")];
864 : }
865 : else
866 : {
867 0 : GNUNET_break (0);
868 0 : return npto;
869 : }
870 : /* exchange_url includes trailing '/' */
871 179 : GNUNET_asprintf (&reserve_url,
872 : "payto://%s/%s%s",
873 : is_http ? "taler-reserve-http" : "taler-reserve",
874 : exchange_url,
875 : pub_str);
876 179 : npto.normalized_payto = reserve_url;
877 179 : return npto;
878 : }
879 :
880 :
881 : /* end of payto.c */
|