LCOV - code coverage report
Current view: top level - lib - merchant_api_common.c (source / functions) Hit Total Coverage
Test: GNU Taler coverage report Lines: 0 179 0.0 %
Date: 2020-08-15 06:12:35 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2020 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 2.1, 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 Lesser General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Lesser General Public License along with
      14             :   TALER; see the file COPYING.LGPL.  If not, see
      15             :   <http://www.gnu.org/licenses/>
      16             : */
      17             : /**
      18             :  * @file lib/merchant_api_common.c
      19             :  * @brief Implementation of common logic for libtalermerchant
      20             :  * @author Christian Grothoff
      21             :  */
      22             : #include "platform.h"
      23             : #include <curl/curl.h>
      24             : #include <jansson.h>
      25             : #include <microhttpd.h> /* just for HTTP status codes */
      26             : #include <gnunet/gnunet_util_lib.h>
      27             : #include <gnunet/gnunet_curl_lib.h>
      28             : #include "taler_merchant_service.h"
      29             : #include <taler/taler_json_lib.h>
      30             : 
      31             : 
      32             : /**
      33             :  * Take a @a response from the merchant API that (presumably) contains
      34             :  * error details and setup the corresponding @a hr structure. Internally
      35             :  * used to convert merchant's responses in to @a hr.
      36             :  *
      37             :  * @param response, if NULL we will report #TALER_EC_INVALID_RESPONSE in `ec
      38             :  * @param http_status http status to use
      39             :  * @param[out] hr response object to initialize, fields will
      40             :  *        only be valid as long as @a response is valid as well
      41             :  */
      42             : void
      43           0 : TALER_MERCHANT_parse_error_details_ (const json_t *response,
      44             :                                      unsigned int http_status,
      45             :                                      struct TALER_MERCHANT_HttpResponse *hr)
      46             : {
      47             :   const json_t *jc;
      48             : 
      49           0 :   memset (hr, 0, sizeof (*hr));
      50           0 :   hr->reply = response;
      51           0 :   hr->http_status = http_status;
      52           0 :   if (NULL == response)
      53             :   {
      54           0 :     hr->ec = TALER_EC_INVALID_RESPONSE;
      55           0 :     return;
      56             :   }
      57           0 :   hr->ec = TALER_JSON_get_error_code (response);
      58           0 :   hr->hint = TALER_JSON_get_error_hint (response);
      59             : 
      60             :   /* handle 'exchange_http_status' */
      61           0 :   jc = json_object_get (response,
      62             :                         "exchange_http_status");
      63             :   /* The caller already knows that the JSON represents an error,
      64             :      so we are dealing with a missing error code here.  */
      65           0 :   if (NULL == jc)
      66           0 :     return; /* no need to bother with exchange_code/hint if we had no status */
      67           0 :   if (! json_is_integer (jc))
      68             :   {
      69           0 :     GNUNET_break_op (0);
      70           0 :     return;
      71             :   }
      72           0 :   hr->exchange_http_status = (unsigned int) json_integer_value (jc);
      73             : 
      74             :   /* handle 'exchange_reply' */
      75           0 :   jc = json_object_get (response,
      76             :                         "exchange_reply");
      77           0 :   if (! json_is_object (jc))
      78             :   {
      79           0 :     GNUNET_break_op (0);
      80             :   }
      81             :   else
      82             :   {
      83           0 :     hr->exchange_reply = jc;
      84             :   }
      85             : 
      86             :   /* handle 'exchange_code' */
      87           0 :   jc = json_object_get (response,
      88             :                         "exchange_code");
      89             :   /* The caller already knows that the JSON represents an error,
      90             :      so we are dealing with a missing error code here.  */
      91           0 :   if (NULL == jc)
      92           0 :     return; /* no need to bother with exchange-hint if we had no code */
      93           0 :   if (! json_is_integer (jc))
      94             :   {
      95           0 :     GNUNET_break_op (0);
      96           0 :     hr->exchange_code = TALER_EC_INVALID;
      97             :   }
      98             :   else
      99             :   {
     100           0 :     hr->exchange_code = (enum TALER_ErrorCode) json_integer_value (jc);
     101             :   }
     102             : 
     103             :   /* handle 'exchange-hint' */
     104           0 :   jc = json_object_get (response,
     105             :                         "exchange-hint");
     106             :   /* The caller already knows that the JSON represents an error,
     107             :      so we are dealing with a missing error code here.  */
     108           0 :   if (NULL == jc)
     109           0 :     return;
     110           0 :   if (! json_is_string (jc))
     111             :   {
     112           0 :     GNUNET_break_op (0);
     113             :   }
     114             :   else
     115             :   {
     116           0 :     hr->exchange_hint = json_string_value (jc);
     117             :   }
     118             : }
     119             : 
     120             : 
     121             : /**
     122             :  * Construct a new base URL using the existing @a base_url
     123             :  * and the given @a instance_id.  The result WILL end with
     124             :  * '/'.
     125             :  *
     126             :  * @param base_url a merchant base URL without "/instances/" in it,
     127             :  *         must not be the empty string; MAY end with '/'.
     128             :  * @param instance_id ID of an instance
     129             :  * @return "${base_url}/instances/${instance_id}/"
     130             :  */
     131             : char *
     132           0 : TALER_MERCHANT_baseurl_add_instance (const char *base_url,
     133             :                                      const char *instance_id)
     134             : {
     135             :   char *ret;
     136             :   bool end_sl;
     137             : 
     138           0 :   if ('\0' == *base_url)
     139             :   {
     140           0 :     GNUNET_break (0);
     141           0 :     return NULL;
     142             :   }
     143           0 :   end_sl = '/' == base_url[strlen (base_url) - 1];
     144             : 
     145           0 :   GNUNET_asprintf (&ret,
     146             :                    (end_sl)
     147             :                    ? "%sinstances/%s/"
     148             :                    : "%s/instances/%s/",
     149             :                    base_url,
     150             :                    instance_id);
     151           0 :   return ret;
     152             : }
     153             : 
     154             : 
     155             : /**
     156             :  * Parses the URI scheme and action of a URI. Ensures that the scheme is either
     157             :  * 'taler' or 'taler+http'.
     158             :  *
     159             :  * @param uri the uri to parse.
     160             :  * @param[out] action the action the URI is indicating.
     161             :  * @param[out] rest the substring of the URI following the action.
     162             :  * @return GNUNET_SYSERR if the URI is malformed, GNUNET_OK otherwise.
     163             :  */
     164             : static int
     165           0 : parse_taler_uri_scheme_action (const char *uri,
     166             :                                char **action,
     167             :                                char **rest)
     168             : {
     169           0 :   char *scheme = GNUNET_strdup (uri);
     170             :   /* Check that the uri starts with "taler://pay" or "taler+http://pay" and
     171             :      then remove it */
     172           0 :   char *path = strchr (scheme, ':');
     173           0 :   if ((NULL == path) ||
     174           0 :       (strlen (path) < 3))
     175             :   {
     176           0 :     GNUNET_free (scheme);
     177           0 :     return GNUNET_SYSERR;
     178             :   }
     179           0 :   path += 3;
     180             : 
     181             :   {
     182           0 :     char path_begin = *path;
     183           0 :     *path = '\0';
     184           0 :     if ((0 != strcmp ("taler://",
     185           0 :                       scheme)) &&
     186           0 :         (0 != strcmp ("taler+http://",
     187             :                       scheme)))
     188             :     {
     189           0 :       GNUNET_free (scheme);
     190           0 :       return GNUNET_SYSERR;
     191             :     }
     192           0 :     *path = path_begin;
     193             :   }
     194             : 
     195             :   {
     196           0 :     char *pqf = strchr (path, '/');
     197           0 :     if (NULL == pqf)
     198             :     {
     199           0 :       GNUNET_free (scheme);
     200           0 :       return GNUNET_SYSERR;
     201             :     }
     202           0 :     *pqf = '\0';
     203           0 :     ++pqf;
     204           0 :     *rest = GNUNET_strdup (pqf);
     205             :   }
     206           0 :   *action = GNUNET_strdup (path);
     207             : 
     208           0 :   GNUNET_free (scheme);
     209           0 :   return GNUNET_OK;
     210             : }
     211             : 
     212             : 
     213             : /**
     214             :  * Extracts information from a taler://pay URI.
     215             :  *
     216             :  * @param pay_uri the URI to parse.
     217             :  * @param[out] parse_data data extracted from the URI. Must be free'd.
     218             :  * @return GNUNET_SYSERR if @e pay_uri is malformed, GNUNET_OK otherwise.
     219             :  */
     220             : int
     221           0 : TALER_MERCHANT_parse_pay_uri (const char *pay_uri,
     222             :                               struct TALER_MERCHANT_PayUriData *parse_data)
     223             : {
     224             :   char *path;
     225             :   {
     226             :     char *action;
     227             : 
     228           0 :     if ((GNUNET_OK !=
     229           0 :          parse_taler_uri_scheme_action (pay_uri,
     230             :                                         &action,
     231           0 :                                         &path)) ||
     232           0 :         (0 != strcmp ("pay",
     233             :                       action)))
     234             :     {
     235           0 :       GNUNET_free (action);
     236           0 :       GNUNET_free (path);
     237           0 :       return GNUNET_SYSERR;
     238             :     }
     239           0 :     GNUNET_free (action);
     240             :   }
     241             : 
     242             :   {
     243             :     char *mpp;
     244             :     char *order_id;
     245           0 :     char *session_id = strrchr (path,
     246             :                                 '/');
     247           0 :     struct TALER_ClaimTokenP *claim_token = NULL;
     248             :     char *ssid;
     249             : 
     250           0 :     if (NULL == session_id)
     251             :     {
     252           0 :       GNUNET_free (path);
     253           0 :       return GNUNET_SYSERR;
     254             :     }
     255           0 :     *session_id = '\0';
     256           0 :     ++session_id;
     257             : 
     258           0 :     order_id = strrchr (path,
     259             :                         '/');
     260           0 :     if (NULL == order_id)
     261             :     {
     262           0 :       GNUNET_free (path);
     263           0 :       return GNUNET_SYSERR;
     264             :     }
     265           0 :     *order_id = '\0';
     266           0 :     ++order_id;
     267             : 
     268             :     {
     269           0 :       char *ct_str = strchr (session_id,
     270             :                              '?');
     271             :       char *ct_data;
     272           0 :       if (NULL != ct_str)
     273             :       {
     274           0 :         *ct_str = '\0';
     275           0 :         ++ct_str;
     276             :       }
     277             : 
     278           0 :       ssid = strchr (session_id,
     279             :                      '#');
     280           0 :       if (NULL != ssid)
     281             :       {
     282           0 :         *ssid = '\0';
     283           0 :         ++ssid;
     284             :       }
     285             : 
     286           0 :       if (NULL != ct_str)
     287             :       {
     288           0 :         ct_data = strchr (ct_str,
     289             :                           '=');
     290           0 :         if (NULL == ct_data)
     291             :         {
     292           0 :           GNUNET_free (order_id);
     293           0 :           return GNUNET_SYSERR;
     294             :         }
     295           0 :         *ct_data = '\0';
     296           0 :         ++ct_data;
     297           0 :         claim_token = GNUNET_new (struct TALER_ClaimTokenP);
     298           0 :         if ((0 != strcmp ("c",
     299           0 :                           ct_str)) ||
     300             :             (GNUNET_OK !=
     301           0 :              GNUNET_STRINGS_string_to_data (ct_data,
     302             :                                             strlen (ct_data),
     303             :                                             claim_token,
     304             :                                             sizeof (*claim_token))))
     305             :         {
     306           0 :           GNUNET_free (order_id);
     307           0 :           GNUNET_free (claim_token);
     308           0 :           return GNUNET_SYSERR;
     309             :         }
     310             :       }
     311             :     }
     312             : 
     313           0 :     mpp = strchr (path,
     314             :                   '/');
     315           0 :     if (NULL != mpp)
     316             :     {
     317           0 :       *mpp = '\0';
     318           0 :       ++mpp;
     319             :     }
     320             : 
     321           0 :     parse_data->merchant_host = GNUNET_strdup (path);
     322           0 :     parse_data->merchant_prefix_path =
     323           0 :       (NULL == mpp) ? NULL : GNUNET_strdup (mpp);
     324           0 :     parse_data->order_id = GNUNET_strdup (order_id);
     325           0 :     parse_data->session_id =
     326           0 :       (0 < strlen (session_id)) ? GNUNET_strdup (session_id) : NULL;
     327           0 :     parse_data->claim_token = claim_token;
     328           0 :     parse_data->ssid =
     329           0 :       (NULL == ssid) ? NULL : GNUNET_strdup (ssid);
     330             :   }
     331           0 :   GNUNET_free (path);
     332           0 :   return GNUNET_OK;
     333             : }
     334             : 
     335             : 
     336             : /**
     337             :  * Frees data contained in the result of parsing a taler://pay URI.
     338             :  *
     339             :  * @param parse_data the data to free.
     340             :  */
     341             : void
     342           0 : TALER_MERCHANT_parse_pay_uri_free (
     343             :   struct TALER_MERCHANT_PayUriData *parse_data)
     344             : {
     345           0 :   GNUNET_free (parse_data->merchant_host);
     346           0 :   GNUNET_free (parse_data->merchant_prefix_path);
     347           0 :   GNUNET_free (parse_data->order_id);
     348           0 :   GNUNET_free (parse_data->session_id);
     349           0 :   GNUNET_free (parse_data->claim_token);
     350           0 :   GNUNET_free (parse_data->ssid);
     351           0 : }
     352             : 
     353             : 
     354             : /**
     355             :  * Extracts information from a taler://refund URI.
     356             :  *
     357             :  * @param refund_uri the URI to parse.
     358             :  * @param[out] parse_data data extracted from the URI. Must be free'd.
     359             :  * @return GNUNET_SYSERR if @e refund_uri is malformed, GNUNET_OK otherwise.
     360             :  */
     361             : int
     362           0 : TALER_MERCHANT_parse_refund_uri (
     363             :   const char *refund_uri,
     364             :   struct TALER_MERCHANT_RefundUriData *parse_data)
     365             : {
     366             :   char *path;
     367             :   {
     368             :     char *action;
     369             : 
     370           0 :     if ((GNUNET_OK !=
     371           0 :          parse_taler_uri_scheme_action (refund_uri,
     372             :                                         &action,
     373           0 :                                         &path)) ||
     374           0 :         (0 != strcmp ("refund",
     375             :                       action)))
     376             :     {
     377           0 :       GNUNET_free (action);
     378           0 :       GNUNET_free (path);
     379           0 :       return GNUNET_SYSERR;
     380             :     }
     381           0 :     GNUNET_free (action);
     382             :   }
     383             : 
     384             :   {
     385             :     char *mpp;
     386             :     char *order_id;
     387           0 :     char *last_seg = strrchr (path,
     388             :                               '/');
     389             :     char *ssid;
     390             : 
     391           0 :     if (NULL == last_seg)
     392             :     {
     393           0 :       GNUNET_free (path);
     394           0 :       return GNUNET_SYSERR;
     395             :     }
     396           0 :     *last_seg = '\0';
     397           0 :     ++last_seg;
     398             : 
     399           0 :     order_id = strrchr (path,
     400             :                         '/');
     401           0 :     if (NULL == order_id)
     402             :     {
     403           0 :       GNUNET_free (path);
     404           0 :       return GNUNET_SYSERR;
     405             :     }
     406           0 :     *order_id = '\0';
     407           0 :     ++order_id;
     408             : 
     409           0 :     ssid = strchr (last_seg,
     410             :                    '#');
     411           0 :     if (NULL != ssid)
     412             :     {
     413           0 :       *ssid = '\0';
     414           0 :       ++ssid;
     415             :     }
     416             : 
     417           0 :     if (0 != strlen (last_seg))
     418             :     {
     419           0 :       GNUNET_free (path);
     420           0 :       return GNUNET_SYSERR;
     421             :     }
     422             : 
     423           0 :     mpp = strchr (path,
     424             :                   '/');
     425           0 :     if (NULL != mpp)
     426             :     {
     427           0 :       *mpp = '\0';
     428           0 :       ++mpp;
     429             :     }
     430             : 
     431           0 :     parse_data->merchant_host = GNUNET_strdup (path);
     432           0 :     parse_data->merchant_prefix_path =
     433           0 :       (NULL == mpp) ? NULL : GNUNET_strdup (mpp);
     434           0 :     parse_data->order_id = GNUNET_strdup (order_id);
     435           0 :     parse_data->ssid =
     436           0 :       (NULL == ssid) ? NULL : GNUNET_strdup (ssid);
     437             :   }
     438           0 :   GNUNET_free (path);
     439           0 :   return GNUNET_OK;
     440             : }
     441             : 
     442             : 
     443             : /**
     444             :  * Frees data contained in the result of parsing a taler://refund URI.
     445             :  *
     446             :  * @param parse_data the data to free.
     447             :  */
     448             : void
     449           0 : TALER_MERCHANT_parse_refund_uri_free (
     450             :   struct TALER_MERCHANT_RefundUriData *parse_data)
     451             : {
     452           0 :   GNUNET_free (parse_data->merchant_host);
     453           0 :   GNUNET_free (parse_data->merchant_prefix_path);
     454           0 :   GNUNET_free (parse_data->order_id);
     455           0 :   GNUNET_free (parse_data->ssid);
     456           0 : }

Generated by: LCOV version 1.14