LCOV - code coverage report
Current view: top level - backend - taler-merchant-httpd_helper.c (source / functions) Hit Total Coverage
Test: GNU Taler merchant coverage report Lines: 75 143 52.4 %
Date: 2021-08-30 06:54:17 Functions: 7 8 87.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   (C) 2014--2021 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Lesser 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 taler-merchant-httpd_helper.c
      18             :  * @brief shared logic for various handlers
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "platform.h"
      22             : #include <gnunet/gnunet_util_lib.h>
      23             : #include <taler/taler_util.h>
      24             : #include <taler/taler_json_lib.h>
      25             : #include "taler-merchant-httpd_helper.h"
      26             : 
      27             : /**
      28             :  * check @a payto_uris for well-formedness
      29             :  *
      30             :  * @param payto_uris JSON array of payto URIs (presumably)
      31             :  * @return true if they are all valid URIs (and this is an array of strings)
      32             :  */
      33             : bool
      34          31 : TMH_payto_uri_array_valid (const json_t *payto_uris)
      35             : {
      36          31 :   bool payto_ok = true;
      37             : 
      38          31 :   if (! json_is_array (payto_uris))
      39             :   {
      40           0 :     GNUNET_break_op (0);
      41           0 :     payto_ok = false;
      42             :   }
      43             :   else
      44             :   {
      45          31 :     unsigned int len = json_array_size (payto_uris);
      46             : 
      47          62 :     for (unsigned int i = 0; i<len; i++)
      48             :     {
      49          31 :       json_t *payto_uri = json_array_get (payto_uris,
      50             :                                           i);
      51             :       const char *uri;
      52             : 
      53          31 :       if (! json_is_string (payto_uri))
      54           0 :         payto_ok = false;
      55          31 :       uri = json_string_value (payto_uri);
      56             :       /* Test for the same payto:// URI being given twice */
      57          32 :       for (unsigned int j = 0; j<i; j++)
      58             :       {
      59           1 :         json_t *old_uri = json_array_get (payto_uris,
      60             :                                           j);
      61           1 :         if (json_equal (payto_uri,
      62             :                         old_uri))
      63             :         {
      64           0 :           GNUNET_break_op (0);
      65           0 :           payto_ok = false;
      66           0 :           break;
      67             :         }
      68             :       }
      69          31 :       if (! payto_ok)
      70           0 :         break;
      71             :       {
      72             :         char *err;
      73             : 
      74          31 :         if (NULL !=
      75          31 :             (err = TALER_payto_validate (uri)))
      76             :         {
      77           0 :           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
      78             :                       "Encountered invalid payto://-URI `%s': %s\n",
      79             :                       uri,
      80             :                       err);
      81           0 :           GNUNET_free (err);
      82           0 :           payto_ok = false;
      83           0 :           break;
      84             :         }
      85             :       }
      86             :     }
      87             :   }
      88          31 :   return payto_ok;
      89             : }
      90             : 
      91             : 
      92             : bool
      93          70 : TMH_location_object_valid (const json_t *location)
      94             : {
      95             :   const char *country;
      96             :   const char *subdivision;
      97             :   const char *district;
      98             :   const char *town;
      99             :   const char *town_loc;
     100             :   const char *postcode;
     101             :   const char *street;
     102             :   const char *building;
     103             :   const char *building_no;
     104          70 :   json_t *lines = NULL;
     105             :   struct GNUNET_JSON_Specification spec[] = {
     106          70 :     GNUNET_JSON_spec_mark_optional (
     107             :       GNUNET_JSON_spec_string ("country",
     108             :                                &country)),
     109          70 :     GNUNET_JSON_spec_mark_optional (
     110             :       GNUNET_JSON_spec_string ("country_subdivision",
     111             :                                &subdivision)),
     112          70 :     GNUNET_JSON_spec_mark_optional (
     113             :       GNUNET_JSON_spec_string ("district",
     114             :                                &district)),
     115          70 :     GNUNET_JSON_spec_mark_optional (
     116             :       GNUNET_JSON_spec_string ("town",
     117             :                                &town)),
     118          70 :     GNUNET_JSON_spec_mark_optional (
     119             :       GNUNET_JSON_spec_string ("town_location",
     120             :                                &town_loc)),
     121          70 :     GNUNET_JSON_spec_mark_optional (
     122             :       GNUNET_JSON_spec_string ("post_code",
     123             :                                &postcode)),
     124          70 :     GNUNET_JSON_spec_mark_optional (
     125             :       GNUNET_JSON_spec_string ("street",
     126             :                                &street)),
     127          70 :     GNUNET_JSON_spec_mark_optional (
     128             :       GNUNET_JSON_spec_string ("building_name",
     129             :                                &building)),
     130          70 :     GNUNET_JSON_spec_mark_optional (
     131             :       GNUNET_JSON_spec_string ("building_number",
     132             :                                &building_no)),
     133          70 :     GNUNET_JSON_spec_mark_optional (
     134             :       GNUNET_JSON_spec_json ("address_lines",
     135             :                              &lines)),
     136          70 :     GNUNET_JSON_spec_end ()
     137             :   };
     138             :   const char *ename;
     139             :   unsigned int eline;
     140             : 
     141          70 :   if (GNUNET_OK !=
     142          70 :       GNUNET_JSON_parse (location,
     143             :                          spec,
     144             :                          &ename,
     145             :                          &eline))
     146             :   {
     147           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     148             :                 "Invalid location for field %s\n",
     149             :                 ename);
     150           0 :     return false;
     151             :   }
     152          70 :   if (NULL != lines)
     153             :   {
     154             :     size_t idx;
     155             :     json_t *line;
     156             : 
     157           0 :     if (! json_is_array (lines))
     158             :     {
     159           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     160             :                   "Invalid location for field %s\n",
     161             :                   "lines");
     162           0 :       return false;
     163             :     }
     164           0 :     json_array_foreach (lines, idx, line)
     165             :     {
     166           0 :       if (! json_is_string (line))
     167             :       {
     168           0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     169             :                     "Invalid address line #%u in location\n",
     170             :                     (unsigned int) idx);
     171           0 :         return false;
     172             :       }
     173             :     }
     174             :   }
     175          70 :   return true;
     176             : }
     177             : 
     178             : 
     179             : bool
     180           0 : TMH_products_array_valid (const json_t *products)
     181             : {
     182             :   const json_t *product;
     183             :   size_t idx;
     184           0 :   bool valid = true;
     185             : 
     186           0 :   if (! json_is_array (products))
     187           0 :     return false;
     188           0 :   json_array_foreach ((json_t *) products, idx, product)
     189             :   {
     190             :     const char *product_id;
     191             :     const char *description;
     192           0 :     json_t *description_i18n = NULL;
     193             :     uint64_t quantity;
     194             :     const char *unit;
     195             :     struct TALER_Amount price;
     196           0 :     const char *image_data_url = NULL;
     197           0 :     json_t *taxes = NULL;
     198             :     struct GNUNET_TIME_Absolute delivery_date;
     199             :     struct GNUNET_JSON_Specification spec[] = {
     200           0 :       GNUNET_JSON_spec_mark_optional (
     201             :         GNUNET_JSON_spec_string ("product_id",
     202             :                                  &product_id)),
     203           0 :       GNUNET_JSON_spec_string ("description",
     204             :                                &description),
     205           0 :       GNUNET_JSON_spec_mark_optional (
     206             :         GNUNET_JSON_spec_json ("description_i18n",
     207             :                                &description_i18n)),
     208           0 :       GNUNET_JSON_spec_mark_optional (
     209             :         GNUNET_JSON_spec_uint64 ("quantity",
     210             :                                  &quantity)),
     211           0 :       GNUNET_JSON_spec_mark_optional (
     212             :         GNUNET_JSON_spec_string ("unit",
     213             :                                  &unit)),
     214           0 :       GNUNET_JSON_spec_mark_optional (
     215             :         TALER_JSON_spec_amount ("price",
     216             :                                 TMH_currency,
     217             :                                 &price)),
     218           0 :       GNUNET_JSON_spec_mark_optional (
     219             :         GNUNET_JSON_spec_string ("image",
     220             :                                  &image_data_url)),
     221           0 :       GNUNET_JSON_spec_mark_optional (
     222             :         GNUNET_JSON_spec_json ("taxes",
     223             :                                &taxes)),
     224           0 :       GNUNET_JSON_spec_mark_optional (
     225             :         GNUNET_JSON_spec_absolute_time ("delivery_date",
     226             :                                         &delivery_date)),
     227           0 :       GNUNET_JSON_spec_end ()
     228             :     };
     229             :     const char *ename;
     230             :     unsigned int eline;
     231             : 
     232           0 :     if (GNUNET_OK !=
     233           0 :         GNUNET_JSON_parse (product,
     234             :                            spec,
     235             :                            &ename,
     236             :                            &eline))
     237             :     {
     238           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     239             :                   "Invalid product #%u for field %s\n",
     240             :                   (unsigned int) idx,
     241             :                   ename);
     242           0 :       return false;
     243             :     }
     244           0 :     if ( (NULL != image_data_url) &&
     245           0 :          (! TMH_image_data_url_valid (image_data_url)) )
     246           0 :       valid = false;
     247           0 :     if ( (NULL != taxes) &&
     248           0 :          (! TMH_taxes_array_valid (taxes)) )
     249           0 :       valid = false;
     250           0 :     if ( (NULL != description_i18n) &&
     251           0 :          (! TALER_JSON_check_i18n (description_i18n)) )
     252           0 :       valid = false;
     253           0 :     GNUNET_JSON_parse_free (spec);
     254           0 :     if (! valid)
     255           0 :       break;
     256             :   }
     257             : 
     258           0 :   return valid;
     259             : }
     260             : 
     261             : 
     262             : bool
     263           8 : TMH_image_data_url_valid (const char *image_data_url)
     264             : {
     265           8 :   if (0 == strcmp (image_data_url,
     266             :                    ""))
     267           5 :     return true;
     268           3 :   if (0 != strncasecmp ("data:image/",
     269             :                         image_data_url,
     270             :                         strlen ("data:image/")))
     271           0 :     return false;
     272           3 :   if (NULL == strstr (image_data_url,
     273             :                       ";base64,"))
     274           0 :     return false;
     275           3 :   if (! TALER_url_valid_charset (image_data_url))
     276           0 :     return false;
     277           3 :   return true;
     278             : }
     279             : 
     280             : 
     281             : bool
     282           8 : TMH_taxes_array_valid (const json_t *taxes)
     283             : {
     284             :   json_t *tax;
     285             :   size_t idx;
     286             : 
     287           8 :   if (! json_is_array (taxes))
     288           0 :     return false;
     289           8 :   json_array_foreach (taxes, idx, tax)
     290             :   {
     291             :     struct TALER_Amount amount;
     292             :     const char *name;
     293             :     struct GNUNET_JSON_Specification spec[] = {
     294           0 :       GNUNET_JSON_spec_string ("name",
     295             :                                &name),
     296           0 :       TALER_JSON_spec_amount_any ("tax",
     297             :                                   &amount),
     298           0 :       GNUNET_JSON_spec_end ()
     299             :     };
     300             :     enum GNUNET_GenericReturnValue res;
     301             : 
     302           0 :     res = TALER_MHD_parse_json_data (NULL,
     303             :                                      tax,
     304             :                                      spec);
     305           0 :     if (GNUNET_OK != res)
     306             :     {
     307           0 :       GNUNET_break_op (0);
     308           0 :       return false;
     309             :     }
     310             :   }
     311           8 :   return true;
     312             : }
     313             : 
     314             : 
     315             : struct TMH_WireMethod *
     316          27 : TMH_setup_wire_account (const char *payto_uri)
     317             : {
     318             :   struct GNUNET_HashCode salt;
     319             :   struct TMH_WireMethod *wm;
     320             : 
     321          27 :   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
     322             :                               &salt,
     323             :                               sizeof (salt));
     324          27 :   wm = GNUNET_new (struct TMH_WireMethod);
     325          27 :   wm->j_wire = GNUNET_JSON_PACK (
     326             :     GNUNET_JSON_pack_string ("payto_uri",
     327             :                              payto_uri),
     328             :     GNUNET_JSON_pack_data_auto ("salt",
     329             :                                 &salt));
     330          27 :   GNUNET_assert (NULL != wm->j_wire);
     331             :   /* This also tests for things like the IBAN being malformed */
     332          27 :   GNUNET_assert (GNUNET_OK ==
     333             :                  TALER_JSON_merchant_wire_signature_hash (wm->j_wire,
     334             :                                                           &wm->h_wire));
     335             :   wm->wire_method
     336          27 :     = TALER_payto_get_method (payto_uri);
     337          27 :   GNUNET_assert (NULL != wm->wire_method);     /* checked earlier */
     338          27 :   wm->active = true;
     339          27 :   return wm;
     340             : }
     341             : 
     342             : 
     343             : enum GNUNET_GenericReturnValue
     344          35 : TMH_check_auth_config (struct MHD_Connection *connection,
     345             :                        const json_t *jauth,
     346             :                        const char **auth_token)
     347             : {
     348          35 :   bool auth_wellformed = false;
     349          35 :   const char *auth_method = json_string_value (json_object_get (jauth,
     350             :                                                                 "method"));
     351          35 :   *auth_token = NULL;
     352          35 :   if (NULL == auth_method)
     353             :   {
     354           0 :     GNUNET_break_op (0);
     355             :   }
     356          35 :   else if (0 == strcmp (auth_method,
     357             :                         "external"))
     358             :   {
     359          27 :     auth_wellformed = true;
     360             :   }
     361           8 :   else if (0 == strcmp (auth_method,
     362             :                         "token"))
     363             :   {
     364           8 :     *auth_token = json_string_value (json_object_get (jauth,
     365             :                                                       "token"));
     366           8 :     if (NULL == *auth_token)
     367             :     {
     368           0 :       GNUNET_break_op (0);
     369             :     }
     370             :     else
     371             :     {
     372           8 :       if (0 != strncasecmp (RFC_8959_PREFIX,
     373             :                             *auth_token,
     374             :                             strlen (RFC_8959_PREFIX)))
     375           1 :         GNUNET_break_op (0);
     376             :       else
     377           7 :         auth_wellformed = true;
     378             :     }
     379             :   }
     380             : 
     381          35 :   if (! auth_wellformed)
     382             :   {
     383           1 :     GNUNET_break_op (0);
     384             :     return (MHD_YES ==
     385           1 :             TALER_MHD_reply_with_error (connection,
     386             :                                         MHD_HTTP_BAD_REQUEST,
     387             :                                         TALER_EC_MERCHANT_PRIVATE_POST_INSTANCES_BAD_AUTH,
     388             :                                         "bad authentication config")) ?
     389           1 :            GNUNET_NO : GNUNET_SYSERR;
     390             :   }
     391          34 :   return GNUNET_OK;
     392             : }
     393             : 
     394             : 
     395             : /**
     396             :  * Generate binary UUID from client-provided UUID-string.
     397             :  *
     398             :  * @param uuids string intpu
     399             :  * @param[out] uuid set to binary UUID
     400             :  */
     401             : void
     402           5 : TMH_uuid_from_string (const char *uuids,
     403             :                       struct GNUNET_Uuid *uuid)
     404             : {
     405             :   struct GNUNET_HashCode hc;
     406             : 
     407           5 :   GNUNET_CRYPTO_hash (uuids,
     408             :                       strlen (uuids),
     409             :                       &hc);
     410             :   GNUNET_static_assert (sizeof (hc) > sizeof (*uuid));
     411           5 :   memcpy (uuid,
     412             :           &hc,
     413             :           sizeof (*uuid));
     414           5 : }

Generated by: LCOV version 1.14