LCOV - code coverage report
Current view: top level - exchange - taler-exchange-httpd_management_extensions.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 0 88 0.0 %
Date: 2022-08-25 06:15:09 Functions: 0 3 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    This file is part of TALER
       3             :    Copyright (C) 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 Affero 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 Affero General Public License for more details.
      12             : 
      13             :    You should have received a copy of the GNU Affero General Public License along with
      14             :    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             :  */
      16             : /**
      17             :  * @file taler-exchange-httpd_management_extensions.c
      18             :  * @brief Handle request to POST /management/extensions
      19             :  * @author Özgür Kesim
      20             :  */
      21             : #include "platform.h"
      22             : #include <gnunet/gnunet_util_lib.h>
      23             : #include <gnunet/gnunet_json_lib.h>
      24             : #include <jansson.h>
      25             : #include <microhttpd.h>
      26             : #include "taler_json_lib.h"
      27             : #include "taler_mhd_lib.h"
      28             : #include "taler_signatures.h"
      29             : #include "taler-exchange-httpd_management.h"
      30             : #include "taler-exchange-httpd_responses.h"
      31             : #include "taler_extensions.h"
      32             : #include "taler_dbevents.h"
      33             : 
      34             : /**
      35             :  * Extension carries the necessary data for a particular extension.
      36             :  *
      37             :  */
      38             : struct Extension
      39             : {
      40             :   enum TALER_Extension_Type type;
      41             :   json_t *config;
      42             : };
      43             : 
      44             : /**
      45             :  * Closure for the #set_extensions transaction
      46             :  */
      47             : struct SetExtensionsContext
      48             : {
      49             :   uint32_t num_extensions;
      50             :   struct Extension *extensions;
      51             :   struct TALER_MasterSignatureP extensions_sig;
      52             : };
      53             : 
      54             : /**
      55             :  * Function implementing database transaction to set the configuration of
      56             :  * extensions.  It runs the transaction logic.
      57             :  *  - IF it returns a non-error code, the transaction logic MUST NOT queue a
      58             :  *    MHD response.
      59             :  *  - IF it returns an hard error, the transaction logic MUST queue a MHD
      60             :  *    response and set @a mhd_ret.
      61             :  *  - IF it returns the soft error code, the function MAY be called again to
      62             :  *    retry and MUST not queue a MHD response.
      63             :  *
      64             :  * @param cls closure with a `struct SetExtensionsContext`
      65             :  * @param connection MHD request which triggered the transaction
      66             :  * @param[out] mhd_ret set to MHD response status for @a connection,
      67             :  *             if transaction failed (!)
      68             :  * @return transaction status
      69             :  */
      70             : static enum GNUNET_DB_QueryStatus
      71           0 : set_extensions (void *cls,
      72             :                 struct MHD_Connection *connection,
      73             :                 MHD_RESULT *mhd_ret)
      74             : {
      75           0 :   struct SetExtensionsContext *sec = cls;
      76             : 
      77             :   /* save the configurations of all extensions */
      78           0 :   for (uint32_t i = 0; i<sec->num_extensions; i++)
      79             :   {
      80           0 :     struct Extension *ext = &sec->extensions[i];
      81             :     const struct TALER_Extension *taler_ext;
      82             :     enum GNUNET_DB_QueryStatus qs;
      83             :     char *config;
      84             : 
      85           0 :     taler_ext = TALER_extensions_get_by_type (ext->type);
      86           0 :     if (NULL == taler_ext)
      87             :     {
      88             :       /* No such extension found */
      89           0 :       GNUNET_break (0);
      90           0 :       return GNUNET_DB_STATUS_HARD_ERROR;
      91             :     }
      92             : 
      93           0 :     GNUNET_assert (NULL != ext->config);
      94             : 
      95           0 :     config = json_dumps (ext->config, JSON_COMPACT | JSON_SORT_KEYS);
      96           0 :     if (NULL == config)
      97             :     {
      98           0 :       GNUNET_break (0);
      99           0 :       *mhd_ret = TALER_MHD_reply_with_error (connection,
     100             :                                              MHD_HTTP_INTERNAL_SERVER_ERROR,
     101             :                                              TALER_EC_GENERIC_JSON_INVALID,
     102             :                                              "convert configuration to string");
     103           0 :       return GNUNET_DB_STATUS_HARD_ERROR;
     104             :     }
     105             : 
     106           0 :     qs = TEH_plugin->set_extension_config (
     107           0 :       TEH_plugin->cls,
     108           0 :       taler_ext->name,
     109             :       config);
     110             : 
     111           0 :     if (qs < 0)
     112             :     {
     113           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     114           0 :         return qs;
     115           0 :       GNUNET_break (0);
     116           0 :       *mhd_ret = TALER_MHD_reply_with_error (connection,
     117             :                                              MHD_HTTP_INTERNAL_SERVER_ERROR,
     118             :                                              TALER_EC_GENERIC_DB_STORE_FAILED,
     119             :                                              "save extension configuration");
     120             :     }
     121             : 
     122             :     /* Success, trigger event */
     123             :     {
     124           0 :       uint32_t nbo_type = htonl (sec->extensions[i].type);
     125           0 :       struct GNUNET_DB_EventHeaderP ev = {
     126           0 :         .size = htons (sizeof (ev)),
     127           0 :         .type = htons (TALER_DBEVENT_EXCHANGE_EXTENSIONS_UPDATED)
     128             :       };
     129             : 
     130           0 :       TEH_plugin->event_notify (TEH_plugin->cls,
     131             :                                 &ev,
     132             :                                 &nbo_type,
     133             :                                 sizeof(nbo_type));
     134             :     }
     135             : 
     136             :   }
     137             : 
     138             :   /* All extensions configured, update the signature */
     139           0 :   TEH_extensions_sig = sec->extensions_sig;
     140             : 
     141           0 :   return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; /* only 'success', so >=0, matters here */
     142             : }
     143             : 
     144             : 
     145             : static enum GNUNET_GenericReturnValue
     146           0 : verify_extensions_from_json (
     147             :   json_t *extensions,
     148             :   struct SetExtensionsContext *sec)
     149             : {
     150             :   const char*name;
     151             :   const struct TALER_Extension *extension;
     152           0 :   size_t i = 0;
     153             :   json_t *blob;
     154             : 
     155           0 :   GNUNET_assert (NULL != extensions);
     156           0 :   GNUNET_assert (json_is_object (extensions));
     157             : 
     158           0 :   sec->num_extensions = json_object_size (extensions);
     159           0 :   sec->extensions = GNUNET_new_array (sec->num_extensions,
     160             :                                       struct Extension);
     161             : 
     162           0 :   json_object_foreach (extensions, name, blob)
     163             :   {
     164           0 :     int critical = 0;
     165             :     json_t *config;
     166           0 :     const char *version = NULL;
     167             : 
     168             :     /* load and verify criticality, version, etc. */
     169           0 :     extension = TALER_extensions_get_by_name (name);
     170           0 :     if (NULL == extension)
     171             :     {
     172           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     173             :                   "no such extension: %s\n", name);
     174           0 :       return GNUNET_SYSERR;
     175             :     }
     176             : 
     177           0 :     if (GNUNET_OK !=
     178           0 :         TALER_extensions_is_json_config (
     179             :           blob, &critical, &version, &config))
     180           0 :       return GNUNET_SYSERR;
     181             : 
     182           0 :     if (critical != extension->critical
     183           0 :         || 0 != strcmp (version, extension->version) // FIXME-oec: libtool compare
     184           0 :         || NULL == config
     185           0 :         || GNUNET_OK != extension->test_json_config (config))
     186           0 :       return GNUNET_SYSERR;
     187             : 
     188           0 :     sec->extensions[i].type = extension->type;
     189           0 :     sec->extensions[i].config = config;
     190             :   }
     191             : 
     192           0 :   return GNUNET_OK;
     193             : }
     194             : 
     195             : 
     196             : MHD_RESULT
     197           0 : TEH_handler_management_post_extensions (
     198             :   struct MHD_Connection *connection,
     199             :   const json_t *root)
     200             : {
     201             :   MHD_RESULT ret;
     202             :   json_t *extensions;
     203           0 :   struct SetExtensionsContext sec = {0};
     204             :   struct GNUNET_JSON_Specification top_spec[] = {
     205           0 :     GNUNET_JSON_spec_json ("extensions",
     206             :                            &extensions),
     207           0 :     GNUNET_JSON_spec_fixed_auto ("extensions_sig",
     208             :                                  &sec.extensions_sig),
     209           0 :     GNUNET_JSON_spec_end ()
     210             :   };
     211             : 
     212             :   /* Parse the top level json structure */
     213             :   {
     214             :     enum GNUNET_GenericReturnValue res;
     215             : 
     216           0 :     res = TALER_MHD_parse_json_data (connection,
     217             :                                      root,
     218             :                                      top_spec);
     219           0 :     if (GNUNET_SYSERR == res)
     220           0 :       return MHD_NO; /* hard failure */
     221           0 :     if (GNUNET_NO == res)
     222           0 :       return MHD_YES; /* failure */
     223             :   }
     224             : 
     225             :   /* Ensure we have an object */
     226           0 :   if (! json_is_object (extensions))
     227             :   {
     228           0 :     GNUNET_JSON_parse_free (top_spec);
     229           0 :     return TALER_MHD_reply_with_error (
     230             :       connection,
     231             :       MHD_HTTP_BAD_REQUEST,
     232             :       TALER_EC_GENERIC_PARAMETER_MALFORMED,
     233             :       "invalid object");
     234             :   }
     235             : 
     236             :   /* Verify the signature */
     237             :   {
     238             :     struct TALER_ExtensionConfigHashP h_config;
     239             : 
     240           0 :     if (GNUNET_OK !=
     241           0 :         TALER_JSON_extensions_config_hash (extensions, &h_config) ||
     242             :         GNUNET_OK !=
     243           0 :         TALER_exchange_offline_extension_config_hash_verify (
     244             :           &h_config,
     245             :           &TEH_master_public_key,
     246             :           &sec.extensions_sig))
     247             :     {
     248           0 :       GNUNET_JSON_parse_free (top_spec);
     249           0 :       return TALER_MHD_reply_with_error (
     250             :         connection,
     251             :         MHD_HTTP_BAD_REQUEST,
     252             :         TALER_EC_GENERIC_PARAMETER_MALFORMED,
     253             :         "invalid signuture");
     254             :     }
     255             :   }
     256             : 
     257           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     258             :               "Received /management/extensions\n");
     259             : 
     260             :   /* Now parse individual extensions and signatures from those objects. */
     261           0 :   if (GNUNET_OK !=
     262           0 :       verify_extensions_from_json (extensions, &sec))
     263             :   {
     264           0 :     GNUNET_JSON_parse_free (top_spec);
     265           0 :     return TALER_MHD_reply_with_error (
     266             :       connection,
     267             :       MHD_HTTP_BAD_REQUEST,
     268             :       TALER_EC_GENERIC_PARAMETER_MALFORMED,
     269             :       "invalid object");
     270             :   }
     271             : 
     272           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     273             :               "Received %u extensions\n",
     274             :               sec.num_extensions);
     275             : 
     276             :   /* now run the transaction to persist the configurations */
     277             :   {
     278             :     enum GNUNET_GenericReturnValue res;
     279             : 
     280           0 :     res = TEH_DB_run_transaction (connection,
     281             :                                   "set extensions",
     282             :                                   TEH_MT_REQUEST_OTHER,
     283             :                                   &ret,
     284             :                                   &set_extensions,
     285             :                                   &sec);
     286             : 
     287           0 :     if (GNUNET_SYSERR == res)
     288           0 :       goto CLEANUP;
     289             :   }
     290             : 
     291           0 :   ret = TALER_MHD_reply_static (
     292             :     connection,
     293             :     MHD_HTTP_NO_CONTENT,
     294             :     NULL,
     295             :     NULL,
     296             :     0);
     297             : 
     298           0 : CLEANUP:
     299           0 :   for (unsigned int i = 0; i < sec.num_extensions; i++)
     300             :   {
     301           0 :     if (NULL != sec.extensions[i].config)
     302             :     {
     303           0 :       json_decref (sec.extensions[i].config);
     304             :     }
     305             :   }
     306           0 :   GNUNET_free (sec.extensions);
     307           0 :   GNUNET_JSON_parse_free (top_spec);
     308           0 :   return ret;
     309             : }
     310             : 
     311             : 
     312             : /* end of taler-exchange-httpd_management_management_post_extensions.c */

Generated by: LCOV version 1.14