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 59 : TALER_full_payto_cmp (const struct TALER_FullPayto a,
33 : const struct TALER_FullPayto b)
34 : {
35 59 : if ( (NULL == a.full_payto) &&
36 0 : (NULL == b.full_payto) )
37 0 : return 0;
38 59 : if (NULL == a.full_payto)
39 0 : return -1;
40 59 : if (NULL == b.full_payto)
41 0 : return 1;
42 59 : return strcmp (a.full_payto,
43 59 : b.full_payto);
44 : }
45 :
46 :
47 : bool
48 402 : TALER_payto_is_wallet (const char *payto_uri)
49 : {
50 : return
51 402 : (0 == strncasecmp (payto_uri,
52 : "payto://taler-reserve/",
53 804 : strlen ("payto://taler-reserve/"))) ||
54 402 : (0 == strncasecmp (payto_uri,
55 : "payto://taler-reserve-http/",
56 : strlen ("payto://taler-reserve-http/")));
57 : }
58 :
59 :
60 : int
61 48 : TALER_normalized_payto_cmp (const struct TALER_NormalizedPayto a,
62 : const struct TALER_NormalizedPayto b)
63 : {
64 48 : if ( (NULL == a.normalized_payto) &&
65 0 : (NULL == b.normalized_payto) )
66 0 : return 0;
67 48 : if (NULL == a.normalized_payto)
68 0 : return -1;
69 48 : if (NULL == b.normalized_payto)
70 0 : return 1;
71 48 : return strcmp (a.normalized_payto,
72 48 : b.normalized_payto);
73 : }
74 :
75 :
76 : void
77 490 : 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 490 : = TALER_payto_normalize (in);
84 490 : 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 490 : TALER_normalized_payto_hash (normalized_payto_uri,
95 : out);
96 490 : 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 32 : TALER_full_payto_normalize_and_cmp (const struct TALER_FullPayto a,
109 : const struct TALER_FullPayto b)
110 : {
111 : struct TALER_NormalizedPayto an
112 32 : = TALER_payto_normalize (a);
113 : struct TALER_NormalizedPayto bn
114 32 : = TALER_payto_normalize (b);
115 : int ret;
116 :
117 32 : ret = TALER_normalized_payto_cmp (an,
118 : bn);
119 32 : GNUNET_free (an.normalized_payto);
120 32 : GNUNET_free (bn.normalized_payto);
121 32 : 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 2328 : payto_get_key (const struct TALER_FullPayto fpayto_uri,
135 : const char *search_key)
136 : {
137 2328 : const char *payto_uri = fpayto_uri.full_payto;
138 : const char *key;
139 : const char *value_start;
140 : const char *value_end;
141 :
142 2328 : key = strchr (payto_uri,
143 : (unsigned char) '?');
144 2328 : if (NULL == key)
145 1 : return NULL;
146 :
147 : do {
148 2327 : if (0 == strncasecmp (++key,
149 : search_key,
150 : strlen (search_key)))
151 : {
152 2327 : value_start = strchr (key,
153 : (unsigned char) '=');
154 2327 : if (NULL == value_start)
155 0 : return NULL;
156 2327 : value_end = strchrnul (value_start,
157 : (unsigned char) '&');
158 :
159 2327 : 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 1230 : TALER_payto_get_method (const char *payto_uri)
178 : {
179 : const char *start;
180 : const char *end;
181 :
182 1230 : if (0 != strncasecmp (payto_uri,
183 : PAYTO,
184 : strlen (PAYTO)))
185 0 : return NULL;
186 1230 : start = &payto_uri[strlen (PAYTO)];
187 1230 : end = strchr (start,
188 : (unsigned char) '/');
189 1230 : if (NULL == end)
190 0 : return NULL;
191 1230 : return GNUNET_strndup (start,
192 : end - start);
193 : }
194 :
195 :
196 : char *
197 389 : 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 389 : 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 389 : host = &payto.full_payto[strlen (PAYTO "x-taler-bank/")];
212 389 : beg = strchr (host,
213 : '/');
214 389 : if (NULL == beg)
215 : {
216 0 : GNUNET_break_op (0);
217 0 : return NULL;
218 : }
219 389 : beg++; /* now points to $ACCOUNT or $PATH */
220 389 : nxt = strchr (beg,
221 : '/');
222 389 : end = strchr (beg,
223 : '?');
224 389 : if (NULL == end)
225 0 : end = &beg[strlen (beg)];
226 391 : while ( (NULL != nxt) &&
227 3 : (end - nxt > 0) )
228 : {
229 2 : beg = nxt + 1;
230 2 : nxt = strchr (beg,
231 : '/');
232 : }
233 389 : 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 2338 : validate_payto_iban (const char *payto_uri)
248 : {
249 2338 : 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 2338 : if (0 != strncasecmp (payto_uri,
257 : IBAN_PREFIX,
258 : strlen (IBAN_PREFIX)))
259 2338 : 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 2338 : 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 2338 : if (0 != strncasecmp (payto_uri,
338 : XTALERBANK_PREFIX,
339 : strlen (XTALERBANK_PREFIX)))
340 6 : return NULL; /* not an x-taler-bank URI */
341 2332 : host = &payto_uri[strlen (XTALERBANK_PREFIX)];
342 : #undef XTALERBANK_PREFIX
343 2332 : beg = strchr (host,
344 : '/');
345 2332 : if (NULL == beg)
346 : {
347 0 : return GNUNET_strdup ("account name missing");
348 : }
349 2332 : beg++; /* now points to $ACCOUNT or $PATH */
350 2332 : nxt = strchr (beg,
351 : '/');
352 2332 : end = strchr (beg,
353 : '?');
354 2332 : if (NULL == end)
355 : {
356 1 : return GNUNET_strdup ("'receiver-name' parameter missing");
357 : }
358 2338 : while ( (NULL != nxt) &&
359 8 : (end - nxt > 0) )
360 : {
361 7 : beg = nxt + 1;
362 7 : nxt = strchr (beg,
363 : '/');
364 : }
365 2331 : user = beg;
366 2331 : if (user == host + 1)
367 : {
368 0 : return GNUNET_strdup ("domain name missing");
369 : }
370 2331 : if ('-' == host[0])
371 1 : return GNUNET_strdup ("invalid character '-' at start of domain name");
372 2330 : dot_ok = false;
373 2330 : post_colon = false;
374 2330 : port_ok = false;
375 23300 : while (host != user)
376 : {
377 23300 : char c = host[0];
378 :
379 23300 : if ('/' == c)
380 : {
381 : /* path started, do not care about characters
382 : in the path */
383 2327 : break;
384 : }
385 20973 : if (':' == c)
386 : {
387 4 : post_colon = true;
388 4 : host++;
389 4 : continue;
390 : }
391 20969 : 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 20959 : 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 20955 : if (! ( ('-' == c) ||
415 20954 : ('_' == c) ||
416 20954 : ( ('0' <= c) && ('9' >= c) ) ||
417 20954 : ( ('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 20955 : dot_ok = true;
428 : }
429 : }
430 20966 : host++;
431 : }
432 2327 : if (post_colon && (! port_ok) )
433 : {
434 1 : return GNUNET_strdup ("port missing after ':'");
435 : }
436 2326 : 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 2338 : payto_validate (const char *payto_uri)
449 : {
450 : char *ret;
451 : const char *start;
452 : const char *end;
453 :
454 2338 : if (0 != strncasecmp (payto_uri,
455 : PAYTO,
456 : strlen (PAYTO)))
457 0 : return GNUNET_strdup ("invalid prefix");
458 120087 : 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 117749 : if (NULL == strchr (ALLOWED_CHARACTERS,
465 117749 : (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 2338 : start = &payto_uri[strlen (PAYTO)];
478 2338 : end = strchr (start,
479 : (unsigned char) '/');
480 2338 : if (NULL == end)
481 0 : return GNUNET_strdup ("missing '/' in payload");
482 :
483 2338 : if (NULL != (ret = validate_payto_iban (payto_uri)))
484 0 : return ret; /* got a definitive answer */
485 2338 : 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 2332 : 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 2332 : TALER_payto_validate (const struct TALER_FullPayto fpayto_uri)
509 : {
510 2332 : const char *payto_uri = fpayto_uri.full_payto;
511 : char *ret;
512 :
513 2332 : ret = payto_validate (payto_uri);
514 2332 : if (NULL != ret)
515 6 : return ret;
516 : {
517 : char *target;
518 :
519 2326 : target = payto_get_key (fpayto_uri,
520 : "receiver-name=");
521 2326 : if (NULL == target)
522 0 : return GNUNET_strdup ("'receiver-name' parameter missing");
523 2326 : GNUNET_free (target);
524 : }
525 :
526 2326 : 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 629 : normalize_payto_x_taler_bank (size_t len,
563 : const char input[static len])
564 629 : {
565 629 : char *res = GNUNET_malloc (len + 1);
566 629 : unsigned int sc = 0;
567 :
568 21579 : for (unsigned int i = 0; i<len; i++)
569 : {
570 20950 : char c = input[i];
571 :
572 20950 : if ('/' == c)
573 2516 : sc++;
574 20950 : if (sc < 4)
575 18870 : res[i] = (char) tolower ((int) c);
576 : else
577 2080 : res[i] = c;
578 : }
579 629 : 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 629 : TALER_payto_normalize (const struct TALER_FullPayto input)
730 : {
731 629 : 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 629 : err = TALER_payto_validate (input);
742 629 : 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 629 : method = TALER_payto_get_method (input.full_payto);
753 629 : if (NULL == method)
754 : {
755 0 : GNUNET_break (0);
756 0 : return npto;
757 : }
758 629 : end = strchr (input.full_payto,
759 : '?');
760 629 : if (NULL == end)
761 0 : end = &input.full_payto[strlen (input.full_payto)];
762 629 : if (0 == strcasecmp (method,
763 : "x-taler-bank"))
764 629 : ret = normalize_payto_x_taler_bank (end - input.full_payto,
765 629 : 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 629 : GNUNET_free (method);
786 629 : npto.normalized_payto = ret;
787 629 : return npto;
788 : }
789 :
790 :
791 : void
792 652 : 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 652 : GNUNET_CRYPTO_hash (npayto.normalized_payto,
799 652 : strlen (npayto.normalized_payto) + 1,
800 : &sha512);
801 : /* truncate */
802 652 : GNUNET_memcpy (h_npayto,
803 : &sha512,
804 : sizeof (*h_npayto));
805 652 : 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 652 : }
810 :
811 :
812 : void
813 650 : 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 650 : GNUNET_CRYPTO_hash (fpayto.full_payto,
820 650 : strlen (fpayto.full_payto) + 1,
821 : &sha512);
822 : /* truncate */
823 650 : GNUNET_memcpy (h_fpayto,
824 : &sha512,
825 : sizeof (*h_fpayto));
826 650 : 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 650 : }
831 :
832 :
833 : struct TALER_NormalizedPayto
834 209 : TALER_reserve_make_payto (const char *exchange_url,
835 : const struct TALER_ReservePublicKeyP *reserve_pub)
836 : {
837 209 : 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 209 : end = GNUNET_STRINGS_data_to_string (
846 : reserve_pub,
847 : sizeof (*reserve_pub),
848 : pub_str,
849 : sizeof (pub_str));
850 209 : *end = '\0';
851 209 : if (0 == strncmp (exchange_url,
852 : "http://",
853 : strlen ("http://")))
854 : {
855 209 : is_http = true;
856 209 : 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 209 : GNUNET_asprintf (&reserve_url,
872 : "payto://%s/%s%s",
873 : is_http ? "taler-reserve-http" : "taler-reserve",
874 : exchange_url,
875 : pub_str);
876 209 : npto.normalized_payto = reserve_url;
877 209 : return npto;
878 : }
879 :
880 :
881 : /* end of payto.c */
|