merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

merchant_api_get-private-otp-devices.c (7464B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2022-2026 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 merchant_api_get-private-otp-devices-new.c
     19  * @brief Implementation of the GET /private/otp-devices request
     20  * @author Christian Grothoff
     21  */
     22 #include "taler/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/taler-merchant/get-private-otp-devices.h>
     29 #include "merchant_api_curl_defaults.h"
     30 #include <taler/taler_json_lib.h>
     31 
     32 /**
     33  * Maximum number of OTP devices we return.
     34  */
     35 #define MAX_OTP 1024
     36 
     37 
     38 /**
     39  * Handle for a GET /private/otp-devices operation.
     40  */
     41 struct TALER_MERCHANT_GetPrivateOtpDevicesHandle
     42 {
     43   /**
     44    * Base URL of the merchant backend.
     45    */
     46   char *base_url;
     47 
     48   /**
     49    * The full URL for this request.
     50    */
     51   char *url;
     52 
     53   /**
     54    * Handle for the request.
     55    */
     56   struct GNUNET_CURL_Job *job;
     57 
     58   /**
     59    * Function to call with the result.
     60    */
     61   TALER_MERCHANT_GetPrivateOtpDevicesCallback cb;
     62 
     63   /**
     64    * Closure for @a cb.
     65    */
     66   TALER_MERCHANT_GET_PRIVATE_OTP_DEVICES_RESULT_CLOSURE *cb_cls;
     67 
     68   /**
     69    * Reference to the execution context.
     70    */
     71   struct GNUNET_CURL_Context *ctx;
     72 };
     73 
     74 
     75 /**
     76  * Parse OTP device information from @a ia.
     77  *
     78  * @param ia JSON array (or NULL!) with otp_device data
     79  * @param[in] ogr partially filled response
     80  * @param gpoh operation handle
     81  * @return #GNUNET_OK on success
     82  */
     83 static enum GNUNET_GenericReturnValue
     84 parse_otp_devices (const json_t *ia,
     85                    struct TALER_MERCHANT_GetPrivateOtpDevicesResponse *ogr,
     86                    struct TALER_MERCHANT_GetPrivateOtpDevicesHandle *gpoh)
     87 {
     88   unsigned int otp_len = (unsigned int) json_array_size (ia);
     89 
     90   if ( (json_array_size (ia) != (size_t) otp_len) ||
     91        (otp_len > MAX_OTP) )
     92   {
     93     GNUNET_break (0);
     94     return GNUNET_SYSERR;
     95   }
     96   {
     97     struct TALER_MERCHANT_GetPrivateOtpDevicesOtpDeviceEntry otp[
     98       GNUNET_NZL (otp_len)];
     99     size_t index;
    100     json_t *value;
    101 
    102     json_array_foreach (ia, index, value) {
    103       struct TALER_MERCHANT_GetPrivateOtpDevicesOtpDeviceEntry *ie =
    104         &otp[index];
    105       struct GNUNET_JSON_Specification spec[] = {
    106         GNUNET_JSON_spec_string ("otp_device_id",
    107                                  &ie->otp_device_id),
    108         GNUNET_JSON_spec_string ("device_description",
    109                                  &ie->otp_device_description),
    110         GNUNET_JSON_spec_end ()
    111       };
    112 
    113       if (GNUNET_OK !=
    114           GNUNET_JSON_parse (value,
    115                              spec,
    116                              NULL, NULL))
    117       {
    118         GNUNET_break_op (0);
    119         return GNUNET_SYSERR;
    120       }
    121     }
    122     ogr->details.ok.otp_devices_length = otp_len;
    123     ogr->details.ok.otp_devices = otp;
    124     gpoh->cb (gpoh->cb_cls,
    125               ogr);
    126     gpoh->cb = NULL;
    127   }
    128   return GNUNET_OK;
    129 }
    130 
    131 
    132 /**
    133  * Function called when we're done processing the
    134  * HTTP GET /private/otp-devices request.
    135  *
    136  * @param cls the `struct TALER_MERCHANT_GetPrivateOtpDevicesHandle`
    137  * @param response_code HTTP response code, 0 on error
    138  * @param response response body, NULL if not in JSON
    139  */
    140 static void
    141 handle_get_otp_devices_finished (void *cls,
    142                                  long response_code,
    143                                  const void *response)
    144 {
    145   struct TALER_MERCHANT_GetPrivateOtpDevicesHandle *gpoh = cls;
    146   const json_t *json = response;
    147   struct TALER_MERCHANT_GetPrivateOtpDevicesResponse ogr = {
    148     .hr.http_status = (unsigned int) response_code,
    149     .hr.reply = json
    150   };
    151 
    152   gpoh->job = NULL;
    153   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    154               "Got /private/otp-devices response with status code %u\n",
    155               (unsigned int) response_code);
    156   switch (response_code)
    157   {
    158   case MHD_HTTP_OK:
    159     {
    160       const json_t *otp_devices;
    161       struct GNUNET_JSON_Specification spec[] = {
    162         GNUNET_JSON_spec_array_const ("otp_devices",
    163                                       &otp_devices),
    164         GNUNET_JSON_spec_end ()
    165       };
    166 
    167       if (GNUNET_OK !=
    168           GNUNET_JSON_parse (json,
    169                              spec,
    170                              NULL, NULL))
    171       {
    172         ogr.hr.http_status = 0;
    173         ogr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    174         break;
    175       }
    176       if (GNUNET_OK ==
    177           parse_otp_devices (otp_devices,
    178                              &ogr,
    179                              gpoh))
    180       {
    181         TALER_MERCHANT_get_private_otp_devices_cancel (gpoh);
    182         return;
    183       }
    184       ogr.hr.http_status = 0;
    185       ogr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    186       break;
    187     }
    188   case MHD_HTTP_UNAUTHORIZED:
    189     ogr.hr.ec = TALER_JSON_get_error_code (json);
    190     ogr.hr.hint = TALER_JSON_get_error_hint (json);
    191     break;
    192   default:
    193     ogr.hr.ec = TALER_JSON_get_error_code (json);
    194     ogr.hr.hint = TALER_JSON_get_error_hint (json);
    195     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    196                 "Unexpected response code %u/%d\n",
    197                 (unsigned int) response_code,
    198                 (int) ogr.hr.ec);
    199     break;
    200   }
    201   gpoh->cb (gpoh->cb_cls,
    202             &ogr);
    203   TALER_MERCHANT_get_private_otp_devices_cancel (gpoh);
    204 }
    205 
    206 
    207 struct TALER_MERCHANT_GetPrivateOtpDevicesHandle *
    208 TALER_MERCHANT_get_private_otp_devices_create (
    209   struct GNUNET_CURL_Context *ctx,
    210   const char *url)
    211 {
    212   struct TALER_MERCHANT_GetPrivateOtpDevicesHandle *gpoh;
    213 
    214   gpoh = GNUNET_new (struct TALER_MERCHANT_GetPrivateOtpDevicesHandle);
    215   gpoh->ctx = ctx;
    216   gpoh->base_url = GNUNET_strdup (url);
    217   return gpoh;
    218 }
    219 
    220 
    221 enum TALER_ErrorCode
    222 TALER_MERCHANT_get_private_otp_devices_start (
    223   struct TALER_MERCHANT_GetPrivateOtpDevicesHandle *gpoh,
    224   TALER_MERCHANT_GetPrivateOtpDevicesCallback cb,
    225   TALER_MERCHANT_GET_PRIVATE_OTP_DEVICES_RESULT_CLOSURE *cb_cls)
    226 {
    227   CURL *eh;
    228 
    229   gpoh->cb = cb;
    230   gpoh->cb_cls = cb_cls;
    231   gpoh->url = TALER_url_join (gpoh->base_url,
    232                               "private/otp-devices",
    233                               NULL);
    234   if (NULL == gpoh->url)
    235     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    236   eh = TALER_MERCHANT_curl_easy_get_ (gpoh->url);
    237   if (NULL == eh)
    238     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    239   gpoh->job = GNUNET_CURL_job_add (gpoh->ctx,
    240                                    eh,
    241                                    &handle_get_otp_devices_finished,
    242                                    gpoh);
    243   if (NULL == gpoh->job)
    244     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    245   return TALER_EC_NONE;
    246 }
    247 
    248 
    249 void
    250 TALER_MERCHANT_get_private_otp_devices_cancel (
    251   struct TALER_MERCHANT_GetPrivateOtpDevicesHandle *gpoh)
    252 {
    253   if (NULL != gpoh->job)
    254   {
    255     GNUNET_CURL_job_cancel (gpoh->job);
    256     gpoh->job = NULL;
    257   }
    258   GNUNET_free (gpoh->url);
    259   GNUNET_free (gpoh->base_url);
    260   GNUNET_free (gpoh);
    261 }
    262 
    263 
    264 /* end of merchant_api_get-private-otp-devices-new.c */