merchant

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

merchant_api_get-private-accounts.c (7408B)


      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-accounts-new.c
     19  * @brief Implementation of the GET /private/accounts 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-accounts.h>
     29 #include "merchant_api_curl_defaults.h"
     30 #include <taler/taler_json_lib.h>
     31 
     32 /**
     33  * Maximum number of accounts permitted.
     34  */
     35 #define MAX_ACCOUNTS 1024
     36 
     37 
     38 /**
     39  * Handle for a GET /private/accounts operation.
     40  */
     41 struct TALER_MERCHANT_GetPrivateAccountsHandle
     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_GetPrivateAccountsCallback cb;
     62 
     63   /**
     64    * Closure for @a cb.
     65    */
     66   TALER_MERCHANT_GET_PRIVATE_ACCOUNTS_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 account information from @a ia.
     77  *
     78  * @param ia JSON array (or NULL!) with account data
     79  * @param[in] tgr partially filled response
     80  * @param gah operation handle
     81  * @return #GNUNET_OK on success
     82  */
     83 static enum GNUNET_GenericReturnValue
     84 parse_accounts (const json_t *ia,
     85                 struct TALER_MERCHANT_GetPrivateAccountsResponse *tgr,
     86                 struct TALER_MERCHANT_GetPrivateAccountsHandle *gah)
     87 {
     88   unsigned int accounts_len = (unsigned int) json_array_size (ia);
     89 
     90   if ( (json_array_size (ia) != (size_t) accounts_len) ||
     91        (accounts_len > MAX_ACCOUNTS) )
     92   {
     93     GNUNET_break (0);
     94     return GNUNET_SYSERR;
     95   }
     96   {
     97     struct TALER_MERCHANT_GetPrivateAccountsAccountEntry accounts[
     98       GNUNET_NZL (accounts_len)];
     99     size_t index;
    100     json_t *value;
    101 
    102     json_array_foreach (ia, index, value) {
    103       struct TALER_MERCHANT_GetPrivateAccountsAccountEntry *ae =
    104         &accounts[index];
    105       struct GNUNET_JSON_Specification spec[] = {
    106         TALER_JSON_spec_full_payto_uri ("payto_uri",
    107                                         &ae->payto_uri),
    108         GNUNET_JSON_spec_fixed_auto ("h_wire",
    109                                      &ae->h_wire),
    110         GNUNET_JSON_spec_bool ("active",
    111                                &ae->active),
    112         GNUNET_JSON_spec_end ()
    113       };
    114 
    115       if (GNUNET_OK !=
    116           GNUNET_JSON_parse (value,
    117                              spec,
    118                              NULL, NULL))
    119       {
    120         GNUNET_break_op (0);
    121         return GNUNET_SYSERR;
    122       }
    123     }
    124     tgr->details.ok.accounts_length = accounts_len;
    125     tgr->details.ok.accounts = accounts;
    126     gah->cb (gah->cb_cls,
    127              tgr);
    128     gah->cb = NULL;
    129   }
    130   return GNUNET_OK;
    131 }
    132 
    133 
    134 /**
    135  * Function called when we're done processing the
    136  * HTTP GET /private/accounts request.
    137  *
    138  * @param cls the `struct TALER_MERCHANT_GetPrivateAccountsHandle`
    139  * @param response_code HTTP response code, 0 on error
    140  * @param response response body, NULL if not in JSON
    141  */
    142 static void
    143 handle_get_accounts_finished (void *cls,
    144                               long response_code,
    145                               const void *response)
    146 {
    147   struct TALER_MERCHANT_GetPrivateAccountsHandle *gah = cls;
    148   const json_t *json = response;
    149   struct TALER_MERCHANT_GetPrivateAccountsResponse tgr = {
    150     .hr.http_status = (unsigned int) response_code,
    151     .hr.reply = json
    152   };
    153 
    154   gah->job = NULL;
    155   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    156               "Got /private/accounts response with status code %u\n",
    157               (unsigned int) response_code);
    158   switch (response_code)
    159   {
    160   case MHD_HTTP_OK:
    161     {
    162       const json_t *accounts;
    163       struct GNUNET_JSON_Specification spec[] = {
    164         GNUNET_JSON_spec_array_const ("accounts",
    165                                       &accounts),
    166         GNUNET_JSON_spec_end ()
    167       };
    168 
    169       if (GNUNET_OK !=
    170           GNUNET_JSON_parse (json,
    171                              spec,
    172                              NULL, NULL))
    173       {
    174         tgr.hr.http_status = 0;
    175         tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    176         break;
    177       }
    178       if (GNUNET_OK ==
    179           parse_accounts (accounts,
    180                           &tgr,
    181                           gah))
    182       {
    183         TALER_MERCHANT_get_private_accounts_cancel (gah);
    184         return;
    185       }
    186       tgr.hr.http_status = 0;
    187       tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    188       break;
    189     }
    190   case MHD_HTTP_UNAUTHORIZED:
    191     tgr.hr.ec = TALER_JSON_get_error_code (json);
    192     tgr.hr.hint = TALER_JSON_get_error_hint (json);
    193     break;
    194   default:
    195     tgr.hr.ec = TALER_JSON_get_error_code (json);
    196     tgr.hr.hint = TALER_JSON_get_error_hint (json);
    197     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    198                 "Unexpected response code %u/%d\n",
    199                 (unsigned int) response_code,
    200                 (int) tgr.hr.ec);
    201     break;
    202   }
    203   gah->cb (gah->cb_cls,
    204            &tgr);
    205   TALER_MERCHANT_get_private_accounts_cancel (gah);
    206 }
    207 
    208 
    209 struct TALER_MERCHANT_GetPrivateAccountsHandle *
    210 TALER_MERCHANT_get_private_accounts_create (
    211   struct GNUNET_CURL_Context *ctx,
    212   const char *url)
    213 {
    214   struct TALER_MERCHANT_GetPrivateAccountsHandle *gah;
    215 
    216   gah = GNUNET_new (struct TALER_MERCHANT_GetPrivateAccountsHandle);
    217   gah->ctx = ctx;
    218   gah->base_url = GNUNET_strdup (url);
    219   return gah;
    220 }
    221 
    222 
    223 enum TALER_ErrorCode
    224 TALER_MERCHANT_get_private_accounts_start (
    225   struct TALER_MERCHANT_GetPrivateAccountsHandle *gah,
    226   TALER_MERCHANT_GetPrivateAccountsCallback cb,
    227   TALER_MERCHANT_GET_PRIVATE_ACCOUNTS_RESULT_CLOSURE *cb_cls)
    228 {
    229   CURL *eh;
    230 
    231   gah->cb = cb;
    232   gah->cb_cls = cb_cls;
    233   gah->url = TALER_url_join (gah->base_url,
    234                              "private/accounts",
    235                              NULL);
    236   if (NULL == gah->url)
    237     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    238   eh = TALER_MERCHANT_curl_easy_get_ (gah->url);
    239   if (NULL == eh)
    240     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    241   gah->job = GNUNET_CURL_job_add (gah->ctx,
    242                                   eh,
    243                                   &handle_get_accounts_finished,
    244                                   gah);
    245   if (NULL == gah->job)
    246     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    247   return TALER_EC_NONE;
    248 }
    249 
    250 
    251 void
    252 TALER_MERCHANT_get_private_accounts_cancel (
    253   struct TALER_MERCHANT_GetPrivateAccountsHandle *gah)
    254 {
    255   if (NULL != gah->job)
    256   {
    257     GNUNET_CURL_job_cancel (gah->job);
    258     gah->job = NULL;
    259   }
    260   GNUNET_free (gah->url);
    261   GNUNET_free (gah->base_url);
    262   GNUNET_free (gah);
    263 }
    264 
    265 
    266 /* end of merchant_api_get-private-accounts-new.c */