LCOV - code coverage report
Current view: top level - util - payto.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 58.7 % 315 185
Test Date: 2026-01-28 06:10:56 Functions: 79.2 % 24 19

            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 "taler/platform.h"
      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          343 : TALER_payto_is_wallet (const char *payto_uri)
      49              : {
      50              :   return
      51          343 :     (0 == strncasecmp (payto_uri,
      52              :                        "payto://taler-reserve/",
      53          686 :                        strlen ("payto://taler-reserve/"))) ||
      54          343 :     (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          395 : 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          395 :     = TALER_payto_normalize (in);
      84          395 :   TALER_normalized_payto_hash (normalized_payto_uri,
      85              :                                out);
      86          395 :   GNUNET_free (normalized_payto_uri.normalized_payto);
      87          395 : }
      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            4 : TALER_full_payto_normalize_and_cmp (const struct TALER_FullPayto a,
      99              :                                     const struct TALER_FullPayto b)
     100              : {
     101              :   struct TALER_NormalizedPayto an
     102            4 :     = TALER_payto_normalize (a);
     103              :   struct TALER_NormalizedPayto bn
     104            4 :     = TALER_payto_normalize (b);
     105              :   int ret;
     106              : 
     107            4 :   ret = TALER_normalized_payto_cmp (an,
     108              :                                     bn);
     109            4 :   GNUNET_free (an.normalized_payto);
     110            4 :   GNUNET_free (bn.normalized_payto);
     111            4 :   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         1736 : payto_get_key (const struct TALER_FullPayto fpayto_uri,
     125              :                const char *search_key)
     126              : {
     127         1736 :   const char *payto_uri = fpayto_uri.full_payto;
     128              :   const char *key;
     129              :   const char *value_start;
     130              :   const char *value_end;
     131              : 
     132         1736 :   key = strchr (payto_uri,
     133              :                 (unsigned char) '?');
     134         1736 :   if (NULL == key)
     135            1 :     return NULL;
     136              : 
     137              :   do {
     138         1735 :     if (0 == strncasecmp (++key,
     139              :                           search_key,
     140              :                           strlen (search_key)))
     141              :     {
     142         1735 :       value_start = strchr (key,
     143              :                             (unsigned char) '=');
     144         1735 :       if (NULL == value_start)
     145            0 :         return NULL;
     146         1735 :       value_end = strchrnul (value_start,
     147              :                              (unsigned char) '&');
     148              : 
     149         1735 :       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          824 : TALER_payto_get_method (const char *payto_uri)
     168              : {
     169              :   const char *start;
     170              :   const char *end;
     171              : 
     172          824 :   if (0 != strncasecmp (payto_uri,
     173              :                         PAYTO,
     174              :                         strlen (PAYTO)))
     175            0 :     return NULL;
     176          824 :   start = &payto_uri[strlen (PAYTO)];
     177          824 :   end = strchr (start,
     178              :                 (unsigned char) '/');
     179          824 :   if (NULL == end)
     180            0 :     return NULL;
     181          824 :   return GNUNET_strndup (start,
     182              :                          end - start);
     183              : }
     184              : 
     185              : 
     186              : char *
     187          335 : 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          335 :   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          335 :   host = &payto.full_payto[strlen (PAYTO "x-taler-bank/")];
     202          335 :   beg = strchr (host,
     203              :                 '/');
     204          335 :   if (NULL == beg)
     205              :   {
     206            0 :     GNUNET_break_op (0);
     207            0 :     return NULL;
     208              :   }
     209          335 :   beg++; /* now points to $ACCOUNT or $PATH */
     210          335 :   nxt = strchr (beg,
     211              :                 '/');
     212          335 :   end = strchr (beg,
     213              :                 '?');
     214          335 :   if (NULL == end)
     215            0 :     end = &beg[strlen (beg)];
     216          337 :   while ( (NULL != nxt) &&
     217            3 :           (end - nxt > 0) )
     218              :   {
     219            2 :     beg = nxt + 1;
     220            2 :     nxt = strchr (beg,
     221              :                   '/');
     222              :   }
     223          335 :   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         1746 : 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         1746 :   if (0 != strncasecmp (payto_uri,
     246              :                         IBAN_PREFIX,
     247              :                         strlen (IBAN_PREFIX)))
     248         1746 :     return NULL; /* not an IBAN */
     249            0 :   iban = strrchr (payto_uri,
     250              :                   '/') + 1;
     251              : #undef IBAN_PREFIX
     252            0 :   q = strchr (iban,
     253              :               '?');
     254            0 :   if (NULL != q)
     255              :   {
     256            0 :     result = GNUNET_strndup (iban,
     257              :                              q - iban);
     258              :   }
     259              :   else
     260              :   {
     261            0 :     result = GNUNET_strdup (iban);
     262              :   }
     263            0 :   if (NULL !=
     264            0 :       (err = TALER_iban_validate (result)))
     265              :   {
     266            0 :     GNUNET_free (result);
     267            0 :     return err;
     268              :   }
     269            0 :   GNUNET_free (result);
     270            0 :   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         1746 : 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         1746 :   if (0 != strncasecmp (payto_uri,
     296              :                         XTALERBANK_PREFIX,
     297              :                         strlen (XTALERBANK_PREFIX)))
     298            6 :     return NULL; /* not an x-taler-bank URI */
     299         1740 :   host = &payto_uri[strlen (XTALERBANK_PREFIX)];
     300              : #undef XTALERBANK_PREFIX
     301         1740 :   beg = strchr (host,
     302              :                 '/');
     303         1740 :   if (NULL == beg)
     304              :   {
     305            0 :     return GNUNET_strdup ("account name missing");
     306              :   }
     307         1740 :   beg++; /* now points to $ACCOUNT or $PATH */
     308         1740 :   nxt = strchr (beg,
     309              :                 '/');
     310         1740 :   end = strchr (beg,
     311              :                 '?');
     312         1740 :   if (NULL == end)
     313              :   {
     314            1 :     return GNUNET_strdup ("'receiver-name' parameter missing");
     315              :   }
     316         1746 :   while ( (NULL != nxt) &&
     317            8 :           (end - nxt > 0) )
     318              :   {
     319            7 :     beg = nxt + 1;
     320            7 :     nxt = strchr (beg,
     321              :                   '/');
     322              :   }
     323         1739 :   user = beg;
     324         1739 :   if (user == host + 1)
     325              :   {
     326            0 :     return GNUNET_strdup ("domain name missing");
     327              :   }
     328         1739 :   if ('-' == host[0])
     329            1 :     return GNUNET_strdup ("invalid character '-' at start of domain name");
     330         1738 :   dot_ok = false;
     331         1738 :   post_colon = false;
     332         1738 :   port_ok = false;
     333        17380 :   while (host != user)
     334              :   {
     335        17380 :     char c = host[0];
     336              : 
     337        17380 :     if ('/' == c)
     338              :     {
     339              :       /* path started, do not care about characters
     340              :          in the path */
     341         1735 :       break;
     342              :     }
     343        15645 :     if (':' == c)
     344              :     {
     345            4 :       post_colon = true;
     346            4 :       host++;
     347            4 :       continue;
     348              :     }
     349        15641 :     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        15631 :       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        15627 :         if (! ( ('-' == c) ||
     373        15626 :                 ('_' == c) ||
     374        15626 :                 ( ('0' <= c) && ('9' >= c) ) ||
     375        15626 :                 ( ('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        15627 :         dot_ok = true;
     386              :       }
     387              :     }
     388        15638 :     host++;
     389              :   }
     390         1735 :   if (post_colon && (! port_ok) )
     391              :   {
     392            1 :     return GNUNET_strdup ("port missing after ':'");
     393              :   }
     394         1734 :   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         1746 : payto_validate (const char *payto_uri)
     407              : {
     408              :   char *ret;
     409              :   const char *start;
     410              :   const char *end;
     411              : 
     412         1746 :   if (0 != strncasecmp (payto_uri,
     413              :                         PAYTO,
     414              :                         strlen (PAYTO)))
     415            0 :     return GNUNET_strdup ("invalid prefix");
     416        88581 :   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        86835 :     if (NULL == strchr (ALLOWED_CHARACTERS,
     423        86835 :                         (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         1746 :   start = &payto_uri[strlen (PAYTO)];
     436         1746 :   end = strchr (start,
     437              :                 (unsigned char) '/');
     438         1746 :   if (NULL == end)
     439            0 :     return GNUNET_strdup ("missing '/' in payload");
     440              : 
     441         1746 :   if (NULL != (ret = validate_payto_iban (payto_uri)))
     442            0 :     return ret; /* got a definitive answer */
     443         1746 :   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         1740 :   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         1740 : TALER_payto_validate (const struct TALER_FullPayto fpayto_uri)
     467              : {
     468         1740 :   const char *payto_uri = fpayto_uri.full_payto;
     469              :   char *ret;
     470              : 
     471         1740 :   ret = payto_validate (payto_uri);
     472         1740 :   if (NULL != ret)
     473            6 :     return ret;
     474              :   {
     475              :     char *target;
     476              : 
     477         1734 :     target = payto_get_key (fpayto_uri,
     478              :                             "receiver-name=");
     479         1734 :     if (NULL == target)
     480            0 :       return GNUNET_strdup ("'receiver-name' parameter missing");
     481         1734 :     GNUNET_free (target);
     482              :   }
     483              : 
     484         1734 :   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          403 : normalize_payto_x_taler_bank (size_t len,
     521              :                               const char input[static len])
     522          403 : {
     523          403 :   char *res = GNUNET_malloc (len + 1);
     524          403 :   unsigned int sc = 0;
     525              : 
     526        13702 :   for (unsigned int i = 0; i<len; i++)
     527              :   {
     528        13299 :     char c = input[i];
     529              : 
     530        13299 :     if ('/' == c)
     531         1612 :       sc++;
     532        13299 :     if (sc < 4)
     533        12090 :       res[i] = (char) tolower ((int) c);
     534              :     else
     535         1209 :       res[i] = c;
     536              :   }
     537          403 :   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            0 : normalize_payto_iban (size_t len,
     554              :                       const char input[static len])
     555            0 : {
     556              :   char *res;
     557            0 :   size_t pos = 0;
     558            0 :   unsigned int sc = 0;
     559              :   bool have_bic;
     560              : 
     561            0 :   for (unsigned int i = 0; i<len; i++)
     562            0 :     if ('/' == input[i])
     563            0 :       sc++;
     564            0 :   if ( (sc > 4) ||
     565              :        (sc < 3) )
     566              :   {
     567            0 :     GNUNET_break (0);
     568            0 :     return NULL;
     569              :   }
     570            0 :   have_bic = (4 == sc);
     571            0 :   res = GNUNET_malloc (len + 1);
     572            0 :   sc = 0;
     573            0 :   for (unsigned int i = 0; i<len; i++)
     574              :   {
     575            0 :     char c = input[i];
     576              : 
     577            0 :     if ('/' == c)
     578            0 :       sc++;
     579            0 :     switch (sc)
     580              :     {
     581            0 :     case 0: /* payto: */
     582              :     case 1: /* / */
     583              :     case 2: /* /iban */
     584            0 :       res[pos++] = (char) tolower ((int) c);
     585            0 :       break;
     586            0 :     case 3: /* /$BIC or /$IBAN */
     587            0 :       if (have_bic)
     588            0 :         continue;
     589            0 :       res[pos++] = (char) toupper ((int) c);
     590            0 :       break;
     591            0 :     case 4: /* /$IBAN */
     592            0 :       res[pos++] = (char) toupper ((int) c);
     593            0 :       break;
     594              :     }
     595              :   }
     596            0 :   GNUNET_assert (pos <= len);
     597            0 :   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          403 : TALER_payto_normalize (const struct TALER_FullPayto input)
     688              : {
     689          403 :   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          403 :     err = TALER_payto_validate (input);
     700          403 :     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          403 :   method = TALER_payto_get_method (input.full_payto);
     711          403 :   if (NULL == method)
     712              :   {
     713            0 :     GNUNET_break (0);
     714            0 :     return npto;
     715              :   }
     716          403 :   end = strchr (input.full_payto,
     717              :                 '?');
     718          403 :   if (NULL == end)
     719            0 :     end = &input.full_payto[strlen (input.full_payto)];
     720          403 :   if (0 == strcasecmp (method,
     721              :                        "x-taler-bank"))
     722          403 :     ret = normalize_payto_x_taler_bank (end - input.full_payto,
     723          403 :                                         input.full_payto);
     724            0 :   else if (0 == strcasecmp (method,
     725              :                             "iban"))
     726            0 :     ret = normalize_payto_iban (end - input.full_payto,
     727            0 :                                 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          403 :   GNUNET_free (method);
     744          403 :   npto.normalized_payto = ret;
     745          403 :   return npto;
     746              : }
     747              : 
     748              : 
     749              : void
     750          509 : TALER_normalized_payto_hash (const struct TALER_NormalizedPayto npayto,
     751              :                              struct TALER_NormalizedPaytoHashP *h_npayto)
     752              : {
     753              :   struct GNUNET_HashCode sha512;
     754              : 
     755          509 :   GNUNET_CRYPTO_hash (npayto.normalized_payto,
     756          509 :                       strlen (npayto.normalized_payto) + 1,
     757              :                       &sha512);
     758              :   GNUNET_static_assert (sizeof (sha512) > sizeof (*h_npayto));
     759              :   /* truncate */
     760          509 :   GNUNET_memcpy (h_npayto,
     761              :                  &sha512,
     762              :                  sizeof (*h_npayto));
     763          509 :   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          509 : }
     768              : 
     769              : 
     770              : void
     771          462 : TALER_full_payto_hash (const struct TALER_FullPayto fpayto,
     772              :                        struct TALER_FullPaytoHashP *h_fpayto)
     773              : {
     774              :   struct GNUNET_HashCode sha512;
     775              : 
     776          462 :   GNUNET_CRYPTO_hash (fpayto.full_payto,
     777          462 :                       strlen (fpayto.full_payto) + 1,
     778              :                       &sha512);
     779              :   GNUNET_static_assert (sizeof (sha512) > sizeof (*h_fpayto));
     780              :   /* truncate */
     781          462 :   GNUNET_memcpy (h_fpayto,
     782              :                  &sha512,
     783              :                  sizeof (*h_fpayto));
     784          462 :   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          462 : }
     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 */
        

Generated by: LCOV version 2.0-1