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