exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

auditor_api_get_config.c (7946B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2023 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
     15   <http://www.gnu.org/licenses/>
     16 */
     17 /**
     18  * @file lib/auditor_api_get_config.c
     19  * @brief Implementation of /config for the auditor's HTTP API
     20  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
     21  * @author Christian Grothoff
     22  */
     23 #include <microhttpd.h>
     24 #include <gnunet/gnunet_curl_lib.h>
     25 #include "taler/taler_json_lib.h"
     26 #include "taler/taler_auditor_service.h"
     27 #include "taler/taler_signatures.h"
     28 #include "auditor_api_curl_defaults.h"
     29 
     30 
     31 /**
     32  * Which revision of the Taler auditor protocol is implemented
     33  * by this library?  Used to determine compatibility.
     34  */
     35 #define TALER_PROTOCOL_CURRENT 1
     36 
     37 /**
     38  * How many revisions back are we compatible to?
     39  */
     40 #define TALER_PROTOCOL_AGE 0
     41 
     42 
     43 /**
     44  * Log error related to CURL operations.
     45  *
     46  * @param type log level
     47  * @param function which function failed to run
     48  * @param code what was the curl error code
     49  */
     50 #define CURL_STRERROR(type, function, code)      \
     51         GNUNET_log (type, \
     52                     "Curl function `%s' has failed at `%s:%d' with error: %s", \
     53                     function, __FILE__, __LINE__, curl_easy_strerror (code));
     54 
     55 
     56 /**
     57  * Handle for the get config request.
     58  */
     59 struct TALER_AUDITOR_GetConfigHandle
     60 {
     61   /**
     62    * The context of this handle
     63    */
     64   struct GNUNET_CURL_Context *ctx;
     65 
     66   /**
     67    * Function to call with the auditor's certification data,
     68    * NULL if this has already been done.
     69    */
     70   TALER_AUDITOR_ConfigCallback config_cb;
     71 
     72   /**
     73    * Closure to pass to @e config_cb.
     74    */
     75   void *config_cb_cls;
     76 
     77   /**
     78    * Data for the request to get the /config of a auditor,
     79    * NULL once we are past stage #MHS_INIT.
     80    */
     81   struct GNUNET_CURL_Job *vr;
     82 
     83   /**
     84    * The url for the @e vr job.
     85    */
     86   char *vr_url;
     87 
     88 };
     89 
     90 
     91 /* ***************** Internal /config fetching ************* */
     92 
     93 /**
     94  * Decode the JSON in @a resp_obj from the /config response and store the data
     95  * in the @a key_data.
     96  *
     97  * @param[in] resp_obj JSON object to parse
     98  * @param[in,out] vi where to store the results we decoded
     99  * @param[out] vc where to store config compatibility data
    100  * @return #TALER_EC_NONE on success
    101  */
    102 static enum TALER_ErrorCode
    103 decode_config_json (const json_t *resp_obj,
    104                     struct TALER_AUDITOR_ConfigInformation *vi,
    105                     enum TALER_AUDITOR_VersionCompatibility *vc)
    106 {
    107   struct TALER_JSON_ProtocolVersion pv;
    108   const char *ver;
    109   struct GNUNET_JSON_Specification spec[] = {
    110     TALER_JSON_spec_version ("version",
    111                              &pv),
    112     GNUNET_JSON_spec_string ("version",
    113                              &ver),
    114     GNUNET_JSON_spec_fixed_auto ("exchange_master_public_key",
    115                                  &vi->exchange_master_public_key),
    116     GNUNET_JSON_spec_fixed_auto ("auditor_public_key",
    117                                  &vi->auditor_pub),
    118     GNUNET_JSON_spec_end ()
    119   };
    120 
    121   if (JSON_OBJECT != json_typeof (resp_obj))
    122   {
    123     GNUNET_break_op (0);
    124     return TALER_EC_GENERIC_JSON_INVALID;
    125   }
    126   /* check the config */
    127   if (GNUNET_OK !=
    128       GNUNET_JSON_parse (resp_obj,
    129                          spec,
    130                          NULL, NULL))
    131   {
    132     GNUNET_break_op (0);
    133     return TALER_EC_GENERIC_JSON_INVALID;
    134   }
    135   vi->version = ver;
    136   *vc = TALER_AUDITOR_VC_MATCH;
    137   if (TALER_PROTOCOL_CURRENT < pv.current)
    138   {
    139     *vc |= TALER_AUDITOR_VC_NEWER;
    140     if (TALER_PROTOCOL_CURRENT < pv.current - pv.age)
    141       *vc |= TALER_AUDITOR_VC_INCOMPATIBLE;
    142   }
    143   if (TALER_PROTOCOL_CURRENT > pv.current)
    144   {
    145     *vc |= TALER_AUDITOR_VC_OLDER;
    146     if (TALER_PROTOCOL_CURRENT - TALER_PROTOCOL_AGE > pv.current)
    147       *vc |= TALER_AUDITOR_VC_INCOMPATIBLE;
    148   }
    149   return TALER_EC_NONE;
    150 }
    151 
    152 
    153 /**
    154  * Callback used when downloading the reply to a /config request
    155  * is complete.
    156  *
    157  * @param cls the `struct TALER_AUDITOR_GetConfigHandle`
    158  * @param response_code HTTP response code, 0 on error
    159  * @param gresp_obj parsed JSON result, NULL on error, must be a `const json_t *`
    160  */
    161 static void
    162 config_completed_cb (void *cls,
    163                      long response_code,
    164                      const void *gresp_obj)
    165 {
    166   struct TALER_AUDITOR_GetConfigHandle *auditor = cls;
    167   const json_t *resp_obj = gresp_obj;
    168   struct TALER_AUDITOR_ConfigResponse vr = {
    169     .hr.reply = resp_obj,
    170     .hr.http_status = (unsigned int) response_code
    171   };
    172 
    173   auditor->vr = NULL;
    174   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    175               "Received config from URL `%s' with status %ld.\n",
    176               auditor->vr_url,
    177               response_code);
    178   switch (response_code)
    179   {
    180   case 0:
    181     GNUNET_break_op (0);
    182     vr.hr.ec = TALER_EC_INVALID;
    183     break;
    184   case MHD_HTTP_OK:
    185     if (NULL == resp_obj)
    186     {
    187       GNUNET_break_op (0);
    188       vr.hr.http_status = 0;
    189       vr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    190       break;
    191     }
    192     vr.hr.ec = decode_config_json (resp_obj,
    193                                    &vr.details.ok.vi,
    194                                    &vr.details.ok.compat);
    195     if (TALER_EC_NONE != vr.hr.ec)
    196     {
    197       GNUNET_break_op (0);
    198       vr.hr.http_status = 0;
    199       break;
    200     }
    201     break;
    202   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    203     vr.hr.ec = TALER_JSON_get_error_code (resp_obj);
    204     vr.hr.hint = TALER_JSON_get_error_hint (resp_obj);
    205     break;
    206   default:
    207     vr.hr.ec = TALER_JSON_get_error_code (resp_obj);
    208     vr.hr.hint = TALER_JSON_get_error_hint (resp_obj);
    209     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    210                 "Unexpected response code %u/%d\n",
    211                 (unsigned int) response_code,
    212                 (int) vr.hr.ec);
    213     break;
    214   }
    215   auditor->config_cb (auditor->config_cb_cls,
    216                       &vr);
    217   TALER_AUDITOR_get_config_cancel (auditor);
    218 }
    219 
    220 
    221 struct TALER_AUDITOR_GetConfigHandle *
    222 TALER_AUDITOR_get_config (struct GNUNET_CURL_Context *ctx,
    223                           const char *url,
    224                           TALER_AUDITOR_ConfigCallback config_cb,
    225                           void *config_cb_cls)
    226 {
    227   struct TALER_AUDITOR_GetConfigHandle *auditor;
    228   CURL *eh;
    229 
    230   auditor = GNUNET_new (struct TALER_AUDITOR_GetConfigHandle);
    231   auditor->config_cb = config_cb;
    232   auditor->config_cb_cls = config_cb_cls;
    233   auditor->ctx = ctx;
    234   auditor->vr_url = TALER_url_join (url,
    235                                     "config",
    236                                     NULL);
    237   if (NULL == auditor->vr_url)
    238   {
    239     GNUNET_break (0);
    240     GNUNET_free (auditor);
    241     return NULL;
    242   }
    243   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    244               "Requesting auditor config with URL `%s'.\n",
    245               auditor->vr_url);
    246   eh = TALER_AUDITOR_curl_easy_get_ (auditor->vr_url);
    247   if (NULL == eh)
    248   {
    249     GNUNET_break (0);
    250     TALER_AUDITOR_get_config_cancel (auditor);
    251     return NULL;
    252   }
    253   GNUNET_break (CURLE_OK ==
    254                 curl_easy_setopt (eh,
    255                                   CURLOPT_TIMEOUT,
    256                                   (long) 300));
    257   auditor->vr = GNUNET_CURL_job_add (auditor->ctx,
    258                                      eh,
    259                                      &config_completed_cb,
    260                                      auditor);
    261   return auditor;
    262 }
    263 
    264 
    265 void
    266 TALER_AUDITOR_get_config_cancel (struct TALER_AUDITOR_GetConfigHandle *auditor)
    267 {
    268   if (NULL != auditor->vr)
    269   {
    270     GNUNET_CURL_job_cancel (auditor->vr);
    271     auditor->vr = NULL;
    272   }
    273   GNUNET_free (auditor->vr_url);
    274   GNUNET_free (auditor);
    275 }
    276 
    277 
    278 /* end of auditor_api_get_config.c */