LCOV - code coverage report
Current view: top level - util - template_parse.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 117 0
Test Date: 2026-04-12 12:58:13 Functions: 0.0 % 7 0

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   (C) 2025 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 util/template_parse.c
      18              :  * @brief shared logic for template contract parsing
      19              :  * @author Bohdan Potuzhnyi
      20              :  */
      21              : #include "taler/platform.h"
      22              : #include <gnunet/gnunet_common.h>
      23              : #include <gnunet/gnunet_json_lib.h>
      24              : #include <jansson.h>
      25              : #include <string.h>
      26              : #include <taler/taler_json_lib.h>
      27              : #include <taler/taler_util.h>
      28              : #include "taler/taler_merchant_util.h"
      29              : #include <regex.h>
      30              : 
      31              : 
      32              : enum TALER_MERCHANT_TemplateType
      33            0 : TALER_MERCHANT_template_type_from_contract (const json_t *template_contract)
      34              : {
      35              :   const json_t *type_val;
      36              : 
      37            0 :   if (NULL == template_contract)
      38            0 :     return TALER_MERCHANT_TEMPLATE_TYPE_INVALID;
      39              : 
      40            0 :   type_val = json_object_get (template_contract,
      41              :                               "template_type");
      42              : 
      43            0 :   if (! json_is_string (type_val))
      44            0 :     return TALER_MERCHANT_TEMPLATE_TYPE_FIXED_ORDER;
      45              : 
      46            0 :   return TALER_MERCHANT_template_type_from_string (
      47              :     json_string_value (type_val));
      48              : }
      49              : 
      50              : 
      51              : enum TALER_MERCHANT_TemplateType
      52            0 : TALER_MERCHANT_template_type_from_string (const char *template_type)
      53              : {
      54            0 :   if (NULL == template_type)
      55            0 :     return TALER_MERCHANT_TEMPLATE_TYPE_FIXED_ORDER;
      56            0 :   if (0 == strcmp (template_type,
      57              :                    "fixed-order"))
      58            0 :     return TALER_MERCHANT_TEMPLATE_TYPE_FIXED_ORDER;
      59            0 :   if (0 == strcmp (template_type,
      60              :                    "inventory-cart"))
      61            0 :     return TALER_MERCHANT_TEMPLATE_TYPE_INVENTORY_CART;
      62            0 :   if (0 == strcmp (template_type,
      63              :                    "paivana"))
      64            0 :     return TALER_MERCHANT_TEMPLATE_TYPE_PAIVANA;
      65            0 :   return TALER_MERCHANT_TEMPLATE_TYPE_INVALID;
      66              : }
      67              : 
      68              : 
      69              : const char *
      70            0 : TALER_MERCHANT_template_type_to_string (
      71              :   enum TALER_MERCHANT_TemplateType template_type)
      72              : {
      73            0 :   switch (template_type)
      74              :   {
      75            0 :   case TALER_MERCHANT_TEMPLATE_TYPE_FIXED_ORDER:
      76            0 :     return "fixed-order";
      77            0 :   case TALER_MERCHANT_TEMPLATE_TYPE_INVENTORY_CART:
      78            0 :     return "inventory-cart";
      79            0 :   case TALER_MERCHANT_TEMPLATE_TYPE_PAIVANA:
      80            0 :     return "paivana";
      81            0 :   case TALER_MERCHANT_TEMPLATE_TYPE_INVALID:
      82            0 :     break;
      83              :   }
      84            0 :   return NULL;
      85              : }
      86              : 
      87              : 
      88              : /**
      89              :  * Parse inventory-specific fields from a template contract.
      90              :  *
      91              :  * @param template_contract json
      92              :  * @param[out] out where to write parsed fields
      93              :  * @param[out] error_name error description
      94              :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on parse/validation failure
      95              :  */
      96              : static enum GNUNET_GenericReturnValue
      97            0 : parse_template_inventory (const json_t *template_contract,
      98              :                           struct TALER_MERCHANT_TemplateContract *out,
      99              :                           const char **error_name)
     100              : {
     101              :   struct GNUNET_JSON_Specification spec[] = {
     102            0 :     GNUNET_JSON_spec_mark_optional (
     103              :       GNUNET_JSON_spec_bool ("selected_all",
     104              :                              &out->details.inventory.selected_all),
     105              :       NULL),
     106            0 :     GNUNET_JSON_spec_mark_optional (
     107              :       GNUNET_JSON_spec_array_const ("selected_categories",
     108              :                                     &out->details.inventory.selected_categories)
     109              :       ,
     110              :       NULL),
     111            0 :     GNUNET_JSON_spec_mark_optional (
     112              :       GNUNET_JSON_spec_array_const ("selected_products",
     113              :                                     &out->details.inventory.selected_products),
     114              :       NULL),
     115            0 :     GNUNET_JSON_spec_mark_optional (
     116              :       GNUNET_JSON_spec_bool ("choose_one",
     117              :                              &out->details.inventory.choose_one),
     118              :       NULL),
     119            0 :     GNUNET_JSON_spec_end ()
     120              :   };
     121              :   const char *en;
     122              : 
     123            0 :   if (GNUNET_OK !=
     124            0 :       GNUNET_JSON_parse ((json_t *) template_contract,
     125              :                          spec,
     126              :                          &en,
     127              :                          NULL))
     128              :   {
     129            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     130              :                 "Invalid inventory template_contract for field %s\n",
     131              :                 en);
     132            0 :     if (NULL != error_name)
     133            0 :       *error_name = en;
     134            0 :     return GNUNET_SYSERR;
     135              :   }
     136              : 
     137            0 :   if (NULL != out->details.inventory.selected_categories)
     138              :   {
     139              :     const json_t *entry;
     140              :     size_t idx;
     141              : 
     142            0 :     json_array_foreach ((json_t *) out->details.inventory.selected_categories,
     143              :                         idx,
     144              :                         entry)
     145              :     {
     146            0 :       if ( (! json_is_integer (entry)) ||
     147            0 :            (0 > json_integer_value (entry)) )
     148              :       {
     149            0 :         GNUNET_break_op (0);
     150            0 :         if (NULL != error_name)
     151            0 :           *error_name = "selected_categories";
     152            0 :         return GNUNET_SYSERR;
     153              :       }
     154              :     }
     155              :   }
     156              : 
     157            0 :   if (NULL != out->details.inventory.selected_products)
     158              :   {
     159              :     const json_t *entry;
     160              :     size_t idx;
     161              : 
     162            0 :     json_array_foreach ((json_t *) out->details.inventory.selected_products,
     163              :                         idx,
     164              :                         entry)
     165              :     {
     166            0 :       if (! json_is_string (entry))
     167              :       {
     168            0 :         GNUNET_break_op (0);
     169            0 :         if (NULL != error_name)
     170            0 :           *error_name = "selected_products";
     171            0 :         return GNUNET_SYSERR;
     172              :       }
     173              :     }
     174              :   }
     175            0 :   return GNUNET_OK;
     176              : }
     177              : 
     178              : 
     179              : /**
     180              :  * Parse paivana-specific fields from a template contract.
     181              :  *
     182              :  * @param template_contract json
     183              :  * @param[out] out where to write parsed fields
     184              :  * @param[out] error_name error description
     185              :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on parse/validation failure
     186              :  */
     187              : static enum GNUNET_GenericReturnValue
     188            0 : parse_template_paivana (const json_t *template_contract,
     189              :                         struct TALER_MERCHANT_TemplateContract *out,
     190              :                         const char **error_name)
     191              : {
     192              :   struct GNUNET_JSON_Specification spec[] = {
     193            0 :     GNUNET_JSON_spec_mark_optional (
     194              :       GNUNET_JSON_spec_string ("website_regex",
     195              :                                &out->details.paivana.website_regex),
     196              :       NULL),
     197            0 :     TALER_MERCHANT_spec_choices ("choices",
     198              :                                  &out->details.paivana.choices,
     199              :                                  &out->details.paivana.choices_len),
     200            0 :     GNUNET_JSON_spec_end ()
     201              :   };
     202              :   const char *en;
     203              : 
     204            0 :   if (GNUNET_OK !=
     205            0 :       GNUNET_JSON_parse ((json_t *) template_contract,
     206              :                          spec,
     207              :                          &en,
     208              :                          NULL))
     209              :   {
     210            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     211              :                 "Invalid paivana template_contract for field %s\n",
     212              :                 en);
     213            0 :     if (NULL != error_name)
     214            0 :       *error_name = en;
     215            0 :     return GNUNET_SYSERR;
     216              :   }
     217            0 :   if (NULL != out->details.paivana.website_regex)
     218              :   {
     219              :     regex_t ex;
     220              : 
     221            0 :     if (0 != regcomp (&ex,
     222              :                       out->details.paivana.website_regex,
     223              :                       REG_NOSUB | REG_EXTENDED))
     224              :     {
     225            0 :       GNUNET_break_op (0);
     226            0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     227              :                   "Invalid paivana website_regex given\n");
     228            0 :       if (NULL != error_name)
     229            0 :         *error_name = "Invalid website_regex given";
     230            0 :       return GNUNET_SYSERR;
     231              :     }
     232            0 :     regfree (&ex);
     233              :   }
     234            0 :   return GNUNET_OK;
     235              : }
     236              : 
     237              : 
     238              : enum GNUNET_GenericReturnValue
     239            0 : TALER_MERCHANT_template_contract_parse (
     240              :   const json_t *template_contract,
     241              :   struct TALER_MERCHANT_TemplateContract *out,
     242              :   const char **error_name)
     243              : {
     244            0 :   const char *template_type_str = NULL;
     245              :   struct GNUNET_JSON_Specification spec[] = {
     246            0 :     GNUNET_JSON_spec_mark_optional (
     247              :       GNUNET_JSON_spec_string ("template_type",
     248              :                                &template_type_str),
     249              :       NULL),
     250            0 :     GNUNET_JSON_spec_mark_optional (
     251              :       GNUNET_JSON_spec_string ("summary",
     252              :                                &out->summary),
     253              :       NULL),
     254            0 :     GNUNET_JSON_spec_mark_optional (
     255              :       GNUNET_JSON_spec_string ("currency",
     256              :                                &out->currency),
     257              :       NULL),
     258            0 :     GNUNET_JSON_spec_mark_optional (
     259              :       TALER_JSON_spec_amount_any ("amount",
     260              :                                   &out->amount),
     261              :       &out->no_amount),
     262            0 :     GNUNET_JSON_spec_mark_optional (
     263              :       GNUNET_JSON_spec_uint32 ("minimum_age",
     264              :                                &out->minimum_age),
     265              :       NULL),
     266            0 :     GNUNET_JSON_spec_mark_optional (
     267              :       GNUNET_JSON_spec_relative_time ("pay_duration",
     268              :                                       &out->pay_duration),
     269              :       NULL),
     270            0 :     GNUNET_JSON_spec_mark_optional (
     271              :       GNUNET_JSON_spec_bool ("request_tip",
     272              :                              &out->request_tip),
     273              :       NULL),
     274            0 :     GNUNET_JSON_spec_end ()
     275              :   };
     276              :   const char *en;
     277              : 
     278            0 :   if (NULL == template_contract)
     279              :   {
     280            0 :     if (NULL != error_name)
     281            0 :       *error_name = "template_contract is NULL";
     282            0 :     return GNUNET_SYSERR;
     283              :   }
     284              : 
     285            0 :   if (GNUNET_OK !=
     286            0 :       GNUNET_JSON_parse ((json_t *) template_contract,
     287              :                          spec,
     288              :                          &en,
     289              :                          NULL))
     290              :   {
     291            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     292              :                 "Invalid input for field %s\n",
     293              :                 en);
     294            0 :     if (NULL != error_name)
     295            0 :       *error_name = en;
     296            0 :     return GNUNET_SYSERR;
     297              :   }
     298              : 
     299            0 :   out->type = TALER_MERCHANT_template_type_from_string (template_type_str);
     300            0 :   if (TALER_MERCHANT_TEMPLATE_TYPE_INVALID == out->type)
     301              :   {
     302            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     303              :                 "Invalid template_type used '%s'\n",
     304              :                 template_type_str);
     305            0 :     if (NULL != error_name)
     306            0 :       *error_name = "Invalid template_type used";
     307            0 :     return GNUNET_SYSERR;
     308              :   }
     309              : 
     310              :   /* Parse additional fields for each specific type */
     311            0 :   switch (out->type)
     312              :   {
     313            0 :   case TALER_MERCHANT_TEMPLATE_TYPE_FIXED_ORDER:
     314            0 :     return GNUNET_OK;
     315            0 :   case TALER_MERCHANT_TEMPLATE_TYPE_INVENTORY_CART:
     316            0 :     return parse_template_inventory (template_contract,
     317              :                                      out,
     318              :                                      error_name);
     319            0 :   case TALER_MERCHANT_TEMPLATE_TYPE_PAIVANA:
     320            0 :     return parse_template_paivana (template_contract,
     321              :                                    out,
     322              :                                    error_name);
     323            0 :   case TALER_MERCHANT_TEMPLATE_TYPE_INVALID:
     324            0 :     break;
     325              :   }
     326              : 
     327              :   /* I think we are never supposed to reach it */
     328            0 :   GNUNET_break_op (0);
     329            0 :   if (NULL != error_name)
     330            0 :     *error_name = "template_type";
     331            0 :   return GNUNET_SYSERR;
     332              : }
     333              : 
     334              : 
     335              : bool
     336            0 : TALER_MERCHANT_template_contract_valid (const json_t *template_contract)
     337              : {
     338              :   struct TALER_MERCHANT_TemplateContract tmp;
     339              : 
     340            0 :   return (GNUNET_OK ==
     341            0 :           TALER_MERCHANT_template_contract_parse (template_contract,
     342              :                                                   &tmp,
     343              :                                                   NULL));
     344              : }
        

Generated by: LCOV version 2.0-1