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: 64 168 38.1 %
Date: 2022-06-30 06:15:34 Functions: 4 8 50.0 %
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           6 : TMH_payto_uri_array_valid (const json_t *payto_uris)
      35             : {
      36           6 :   bool payto_ok = true;
      37             : 
      38           6 :   if (! json_is_array (payto_uris))
      39             :   {
      40           0 :     GNUNET_break_op (0);
      41           0 :     payto_ok = false;
      42             :   }
      43             :   else
      44             :   {
      45           6 :     unsigned int len = json_array_size (payto_uris);
      46             : 
      47          12 :     for (unsigned int i = 0; i<len; i++)
      48             :     {
      49           6 :       json_t *payto_uri = json_array_get (payto_uris,
      50             :                                           i);
      51             :       const char *uri;
      52             : 
      53           6 :       if (! json_is_string (payto_uri))
      54           0 :         payto_ok = false;
      55           6 :       uri = json_string_value (payto_uri);
      56             :       /* Test for the same payto:// URI being given twice */
      57           6 :       for (unsigned int j = 0; j<i; j++)
      58             :       {
      59           0 :         json_t *old_uri = json_array_get (payto_uris,
      60             :                                           j);
      61           0 :         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           6 :       if (! payto_ok)
      70           0 :         break;
      71             :       {
      72             :         char *err;
      73             : 
      74           6 :         if (NULL !=
      75           6 :             (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           6 :   return payto_ok;
      89             : }
      90             : 
      91             : 
      92             : bool
      93          12 : TMH_location_object_valid (const json_t *location)
      94             : {
      95          12 :   const char *country = NULL;
      96          12 :   const char *subdivision = NULL;
      97          12 :   const char *district = NULL;
      98          12 :   const char *town = NULL;
      99          12 :   const char *town_loc = NULL;
     100          12 :   const char *postcode = NULL;
     101          12 :   const char *street = NULL;
     102          12 :   const char *building = NULL;
     103          12 :   const char *building_no = NULL;
     104          12 :   json_t *lines = NULL;
     105             :   struct GNUNET_JSON_Specification spec[] = {
     106          12 :     GNUNET_JSON_spec_mark_optional (
     107             :       GNUNET_JSON_spec_string ("country",
     108             :                                &country),
     109             :       NULL),
     110          12 :     GNUNET_JSON_spec_mark_optional (
     111             :       GNUNET_JSON_spec_string ("country_subdivision",
     112             :                                &subdivision),
     113             :       NULL),
     114          12 :     GNUNET_JSON_spec_mark_optional (
     115             :       GNUNET_JSON_spec_string ("district",
     116             :                                &district),
     117             :       NULL),
     118          12 :     GNUNET_JSON_spec_mark_optional (
     119             :       GNUNET_JSON_spec_string ("town",
     120             :                                &town),
     121             :       NULL),
     122          12 :     GNUNET_JSON_spec_mark_optional (
     123             :       GNUNET_JSON_spec_string ("town_location",
     124             :                                &town_loc),
     125             :       NULL),
     126          12 :     GNUNET_JSON_spec_mark_optional (
     127             :       GNUNET_JSON_spec_string ("post_code",
     128             :                                &postcode),
     129             :       NULL),
     130          12 :     GNUNET_JSON_spec_mark_optional (
     131             :       GNUNET_JSON_spec_string ("street",
     132             :                                &street),
     133             :       NULL),
     134          12 :     GNUNET_JSON_spec_mark_optional (
     135             :       GNUNET_JSON_spec_string ("building_name",
     136             :                                &building),
     137             :       NULL),
     138          12 :     GNUNET_JSON_spec_mark_optional (
     139             :       GNUNET_JSON_spec_string ("building_number",
     140             :                                &building_no),
     141             :       NULL),
     142          12 :     GNUNET_JSON_spec_mark_optional (
     143             :       GNUNET_JSON_spec_json ("address_lines",
     144             :                              &lines),
     145             :       NULL),
     146          12 :     GNUNET_JSON_spec_end ()
     147             :   };
     148             :   const char *ename;
     149             :   unsigned int eline;
     150             : 
     151          12 :   if (GNUNET_OK !=
     152          12 :       GNUNET_JSON_parse (location,
     153             :                          spec,
     154             :                          &ename,
     155             :                          &eline))
     156             :   {
     157           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     158             :                 "Invalid location for field %s\n",
     159             :                 ename);
     160           0 :     return false;
     161             :   }
     162          12 :   if (NULL != lines)
     163             :   {
     164             :     size_t idx;
     165             :     json_t *line;
     166             : 
     167           0 :     if (! json_is_array (lines))
     168             :     {
     169           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     170             :                   "Invalid location for field %s\n",
     171             :                   "lines");
     172           0 :       return false;
     173             :     }
     174           0 :     json_array_foreach (lines, idx, line)
     175             :     {
     176           0 :       if (! json_is_string (line))
     177             :       {
     178           0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     179             :                     "Invalid address line #%u in location\n",
     180             :                     (unsigned int) idx);
     181           0 :         return false;
     182             :       }
     183             :     }
     184             :   }
     185          12 :   return true;
     186             : }
     187             : 
     188             : 
     189             : bool
     190           0 : TMH_products_array_valid (const json_t *products)
     191             : {
     192             :   const json_t *product;
     193             :   size_t idx;
     194           0 :   bool valid = true;
     195             : 
     196           0 :   if (! json_is_array (products))
     197             :   {
     198           0 :     GNUNET_break_op (0);
     199           0 :     return false;
     200             :   }
     201           0 :   json_array_foreach ((json_t *) products, idx, product)
     202             :   {
     203           0 :     const char *product_id = NULL;
     204             :     const char *description;
     205           0 :     json_t *description_i18n = NULL;
     206           0 :     uint64_t quantity = 0;
     207           0 :     const char *unit = NULL;
     208           0 :     struct TALER_Amount price = { .value = 0 };
     209           0 :     const char *image_data_url = NULL;
     210           0 :     json_t *taxes = NULL;
     211           0 :     struct GNUNET_TIME_Timestamp delivery_date = { 0 };
     212             :     struct GNUNET_JSON_Specification spec[] = {
     213           0 :       GNUNET_JSON_spec_mark_optional (
     214             :         GNUNET_JSON_spec_string ("product_id",
     215             :                                  &product_id),
     216             :         NULL),
     217           0 :       GNUNET_JSON_spec_string ("description",
     218             :                                &description),
     219           0 :       GNUNET_JSON_spec_mark_optional (
     220             :         GNUNET_JSON_spec_json ("description_i18n",
     221             :                                &description_i18n),
     222             :         NULL),
     223           0 :       GNUNET_JSON_spec_mark_optional (
     224             :         GNUNET_JSON_spec_uint64 ("quantity",
     225             :                                  &quantity),
     226             :         NULL),
     227           0 :       GNUNET_JSON_spec_mark_optional (
     228             :         GNUNET_JSON_spec_string ("unit",
     229             :                                  &unit),
     230             :         NULL),
     231           0 :       GNUNET_JSON_spec_mark_optional (
     232             :         TALER_JSON_spec_amount ("price",
     233             :                                 TMH_currency,
     234             :                                 &price),
     235             :         NULL),
     236           0 :       GNUNET_JSON_spec_mark_optional (
     237             :         GNUNET_JSON_spec_string ("image",
     238             :                                  &image_data_url),
     239             :         NULL),
     240           0 :       GNUNET_JSON_spec_mark_optional (
     241             :         GNUNET_JSON_spec_json ("taxes",
     242             :                                &taxes),
     243             :         NULL),
     244           0 :       GNUNET_JSON_spec_mark_optional (
     245             :         GNUNET_JSON_spec_timestamp ("delivery_date",
     246             :                                     &delivery_date),
     247             :         NULL),
     248           0 :       GNUNET_JSON_spec_end ()
     249             :     };
     250             :     const char *ename;
     251             :     unsigned int eline;
     252             : 
     253           0 :     if (GNUNET_OK !=
     254           0 :         GNUNET_JSON_parse (product,
     255             :                            spec,
     256             :                            &ename,
     257             :                            &eline))
     258             :     {
     259           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     260             :                   "Invalid product #%u for field %s\n",
     261             :                   (unsigned int) idx,
     262             :                   ename);
     263           0 :       return false;
     264             :     }
     265           0 :     if ( (NULL != image_data_url) &&
     266           0 :          (! TMH_image_data_url_valid (image_data_url)) )
     267             :     {
     268           0 :       GNUNET_break_op (0);
     269           0 :       valid = false;
     270             :     }
     271           0 :     if ( (NULL != taxes) &&
     272           0 :          (! TMH_taxes_array_valid (taxes)) )
     273             :     {
     274           0 :         GNUNET_break_op (0);
     275           0 :         valid = false;
     276             :     }
     277           0 :     if ( (NULL != description_i18n) &&
     278           0 :          (! TALER_JSON_check_i18n (description_i18n)) )
     279             :     {
     280           0 :       GNUNET_break_op (0);
     281           0 :       valid = false;
     282             :     }
     283           0 :     GNUNET_JSON_parse_free (spec);
     284           0 :     if (! valid)
     285           0 :       break;
     286             :   }
     287             : 
     288           0 :   return valid;
     289             : }
     290             : 
     291             : 
     292             : bool
     293           0 : TMH_image_data_url_valid (const char *image_data_url)
     294             : {
     295           0 :   if (0 == strcmp (image_data_url,
     296             :                    ""))
     297           0 :     return true;
     298           0 :   if (0 != strncasecmp ("data:image/",
     299             :                         image_data_url,
     300             :                         strlen ("data:image/")))
     301             :   {
     302           0 :     GNUNET_break_op (0);
     303           0 :     return false;
     304             :   }
     305           0 :   if (NULL == strstr (image_data_url,
     306             :                       ";base64,"))
     307             :   {
     308           0 :     GNUNET_break_op (0);
     309           0 :     return false;
     310             :   }
     311           0 :   if (! TALER_url_valid_charset (image_data_url))
     312             :   {
     313           0 :     GNUNET_break_op (0);
     314           0 :     return false;
     315             :   }
     316           0 :   return true;
     317             : }
     318             : 
     319             : 
     320             : bool
     321           0 : TMH_taxes_array_valid (const json_t *taxes)
     322             : {
     323             :   json_t *tax;
     324             :   size_t idx;
     325             : 
     326           0 :   if (! json_is_array (taxes))
     327           0 :     return false;
     328           0 :   json_array_foreach (taxes, idx, tax)
     329             :   {
     330             :     struct TALER_Amount amount;
     331             :     const char *name;
     332             :     struct GNUNET_JSON_Specification spec[] = {
     333           0 :       GNUNET_JSON_spec_string ("name",
     334             :                                &name),
     335           0 :       TALER_JSON_spec_amount_any ("tax",
     336             :                                   &amount),
     337           0 :       GNUNET_JSON_spec_end ()
     338             :     };
     339             :     enum GNUNET_GenericReturnValue res;
     340             : 
     341           0 :     res = TALER_MHD_parse_json_data (NULL,
     342             :                                      tax,
     343             :                                      spec);
     344           0 :     if (GNUNET_OK != res)
     345             :     {
     346           0 :       GNUNET_break_op (0);
     347           0 :       return false;
     348             :     }
     349             :   }
     350           0 :   return true;
     351             : }
     352             : 
     353             : 
     354             : struct TMH_WireMethod *
     355           6 : TMH_setup_wire_account (const char *payto_uri)
     356             : {
     357             :   struct TMH_WireMethod *wm;
     358             :   char *emsg;
     359             : 
     360           6 :   if (NULL != (emsg = TALER_payto_validate (payto_uri)))
     361             :   {
     362           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     363             :                 "Invalid URI `%s': %s\n",
     364             :                 payto_uri,
     365             :                 emsg);
     366           0 :     GNUNET_free (emsg);
     367           0 :     return NULL;
     368             :   }
     369             : 
     370           6 :   wm = GNUNET_new (struct TMH_WireMethod);
     371           6 :   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
     372           6 :                               &wm->wire_salt,
     373             :                               sizeof (wm->wire_salt));
     374           6 :   wm->payto_uri = GNUNET_strdup (payto_uri);
     375           6 :   TALER_merchant_wire_signature_hash (payto_uri,
     376           6 :                                       &wm->wire_salt,
     377             :                                       &wm->h_wire);
     378             :   wm->wire_method
     379           6 :     = TALER_payto_get_method (payto_uri);
     380           6 :   wm->active = true;
     381           6 :   return wm;
     382             : }
     383             : 
     384             : 
     385             : enum GNUNET_GenericReturnValue
     386           8 : TMH_check_auth_config (struct MHD_Connection *connection,
     387             :                        const json_t *jauth,
     388             :                        const char **auth_token)
     389             : {
     390           8 :   bool auth_wellformed = false;
     391           8 :   const char *auth_method = json_string_value (json_object_get (jauth,
     392             :                                                                 "method"));
     393             : 
     394           8 :   *auth_token = NULL;
     395           8 :   if (NULL == auth_method)
     396             :   {
     397           0 :     GNUNET_break_op (0);
     398             :   }
     399           8 :   else if (0 == strcmp (auth_method,
     400             :                         "external"))
     401             :   {
     402           4 :     auth_wellformed = true;
     403             :   }
     404           4 :   else if (0 == strcmp (auth_method,
     405             :                         "token"))
     406             :   {
     407           4 :     *auth_token = json_string_value (json_object_get (jauth,
     408             :                                                       "token"));
     409           4 :     if (NULL == *auth_token)
     410             :     {
     411           0 :       GNUNET_break_op (0);
     412             :     }
     413             :     else
     414             :     {
     415           4 :       if (0 != strncasecmp (RFC_8959_PREFIX,
     416             :                             *auth_token,
     417             :                             strlen (RFC_8959_PREFIX)))
     418           0 :         GNUNET_break_op (0);
     419             :       else
     420           4 :         auth_wellformed = true;
     421             :     }
     422             :   }
     423             : 
     424           8 :   if (! auth_wellformed)
     425             :   {
     426           0 :     GNUNET_break_op (0);
     427             :     return (MHD_YES ==
     428           0 :             TALER_MHD_reply_with_error (connection,
     429             :                                         MHD_HTTP_BAD_REQUEST,
     430             :                                         TALER_EC_MERCHANT_PRIVATE_POST_INSTANCES_BAD_AUTH,
     431             :                                         "bad authentication config")) ?
     432           0 :            GNUNET_NO : GNUNET_SYSERR;
     433             :   }
     434           8 :   return GNUNET_OK;
     435             : }
     436             : 
     437             : 
     438             : /**
     439             :  * Generate binary UUID from client-provided UUID-string.
     440             :  *
     441             :  * @param uuids string intpu
     442             :  * @param[out] uuid set to binary UUID
     443             :  */
     444             : void
     445           0 : TMH_uuid_from_string (const char *uuids,
     446             :                       struct GNUNET_Uuid *uuid)
     447             : {
     448             :   struct GNUNET_HashCode hc;
     449             : 
     450           0 :   GNUNET_CRYPTO_hash (uuids,
     451             :                       strlen (uuids),
     452             :                       &hc);
     453             :   GNUNET_static_assert (sizeof (hc) > sizeof (*uuid));
     454           0 :   memcpy (uuid,
     455             :           &hc,
     456             :           sizeof (*uuid));
     457           0 : }

Generated by: LCOV version 1.14