merchant

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

taler-merchant-httpd_post-private-fountains.c (6272B)


      1 /*
      2   This file is part of TALER
      3   (C) 2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify
      6   it under the terms of the GNU Affero General Public License as
      7   published by the Free Software Foundation; either version 3,
      8   or (at your option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful, but
     11   WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU General Public License for more details.
     14 
     15   You should have received a copy of the GNU General Public
     16   License along with TALER; see the file COPYING.  If not,
     17   see <http://www.gnu.org/licenses/>
     18 */
     19 
     20 /**
     21  * @file src/backend/taler-merchant-httpd_post-private-fountains.c
     22  * @brief implementing POST /private/fountains request handling
     23  * @author Bohdan Potuzhnyi
     24  */
     25 #include "platform.h"
     26 #include "taler-merchant-httpd_post-private-fountains.h"
     27 #include "taler-merchant-httpd_helper.h"
     28 #include "taler-merchant-httpd_fountains.h"
     29 #include <taler/taler_json_lib.h>
     30 #include "merchant-database/do_insert_fountain.h"
     31 
     32 
     33 /**
     34  * How often do we retry on a (astronomically unlikely) random
     35  * collision of the fountain identifier or secret?
     36  */
     37 #define MAX_RETRIES 3
     38 
     39 
     40 enum MHD_Result
     41 TMH_private_post_fountains (const struct TMH_RequestHandler *rh,
     42                             struct MHD_Connection *connection,
     43                             struct TMH_HandlerContext *hc)
     44 {
     45   struct TMH_MerchantInstance *mi = hc->instance;
     46   const char *description;
     47   struct GNUNET_TIME_Relative poll_freq;
     48   const json_t *jgrants;
     49   struct GNUNET_JSON_Specification spec[] = {
     50     GNUNET_JSON_spec_string ("description",
     51                              &description),
     52     GNUNET_JSON_spec_relative_time ("poll_freq",
     53                                     &poll_freq),
     54     GNUNET_JSON_spec_array_const ("grants",
     55                                   &jgrants),
     56     GNUNET_JSON_spec_end ()
     57   };
     58   unsigned int grants_len;
     59 
     60   GNUNET_assert (NULL != mi);
     61   {
     62     enum GNUNET_GenericReturnValue res;
     63 
     64     res = TALER_MHD_parse_json_data (connection,
     65                                      hc->request_body,
     66                                      spec);
     67     if (GNUNET_OK != res)
     68     {
     69       GNUNET_break_op (0);
     70       return (GNUNET_NO == res)
     71              ? MHD_YES
     72              : MHD_NO;
     73     }
     74   }
     75   {
     76     struct TALER_MERCHANTDB_FountainGrant grants[TMH_MAX_FOUNTAIN_GRANTS];
     77     enum GNUNET_GenericReturnValue res;
     78 
     79     res = TMH_fountain_grants_parse (connection,
     80                                      jgrants,
     81                                      grants,
     82                                      &grants_len);
     83     if (GNUNET_OK != res)
     84     {
     85       GNUNET_JSON_parse_free (spec);
     86       return (GNUNET_NO == res)
     87              ? MHD_YES
     88              : MHD_NO;
     89     }
     90 
     91     for (unsigned int attempt = 0; attempt < MAX_RETRIES; attempt++)
     92     {
     93       char secret[32];
     94       struct GNUNET_HashCode h_secret;
     95       char *fountain_id;
     96       char *fountain_secret;
     97       char *unknown_slug;
     98       bool conflict;
     99       enum GNUNET_DB_QueryStatus qs;
    100 
    101       GNUNET_CRYPTO_random_block (secret,
    102                                   sizeof (secret));
    103       GNUNET_CRYPTO_hash (secret,
    104                           sizeof (secret),
    105                           &h_secret);
    106       {
    107         char rnd[16];
    108 
    109         GNUNET_CRYPTO_random_block (rnd,
    110                                     sizeof (rnd));
    111         fountain_id = GNUNET_STRINGS_data_to_string_alloc (rnd,
    112                                                            sizeof (rnd));
    113       }
    114       qs = TALER_MERCHANTDB_do_insert_fountain (TMH_db,
    115                                                 mi->settings.id,
    116                                                 fountain_id,
    117                                                 &h_secret,
    118                                                 description,
    119                                                 poll_freq,
    120                                                 grants_len,
    121                                                 grants,
    122                                                 &unknown_slug,
    123                                                 &conflict);
    124       if (qs < 0)
    125       {
    126         GNUNET_break (0);
    127         GNUNET_free (fountain_id);
    128         GNUNET_JSON_parse_free (spec);
    129         return TALER_MHD_reply_with_error (connection,
    130                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    131                                            TALER_EC_GENERIC_DB_STORE_FAILED,
    132                                            "do_insert_fountain");
    133       }
    134       if (NULL != unknown_slug)
    135       {
    136         enum MHD_Result mret;
    137 
    138         GNUNET_free (fountain_id);
    139         GNUNET_JSON_parse_free (spec);
    140         mret = TALER_MHD_reply_with_error (
    141           connection,
    142           MHD_HTTP_NOT_FOUND,
    143           TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_TOKEN_FAMILY_SLUG_UNKNOWN,
    144           unknown_slug);
    145         GNUNET_free (unknown_slug);
    146         return mret;
    147       }
    148       if (conflict)
    149       {
    150         /* Random collision of fountain_id or secret hash; try again
    151            with fresh randomness. */
    152         GNUNET_free (fountain_id);
    153         continue;
    154       }
    155       fountain_secret = GNUNET_STRINGS_data_to_string_alloc (secret,
    156                                                              sizeof (secret));
    157       memset (secret,
    158               0,
    159               sizeof (secret));
    160       GNUNET_JSON_parse_free (spec);
    161       {
    162         enum MHD_Result mret;
    163 
    164         mret = TALER_MHD_REPLY_JSON_PACK (
    165           connection,
    166           MHD_HTTP_OK,
    167           GNUNET_JSON_pack_string ("fountain_id",
    168                                    fountain_id),
    169           GNUNET_JSON_pack_string ("fountain_secret",
    170                                    fountain_secret));
    171         GNUNET_free (fountain_id);
    172         GNUNET_free (fountain_secret);
    173         return mret;
    174       }
    175     }
    176   }
    177   GNUNET_break (0);
    178   GNUNET_JSON_parse_free (spec);
    179   return TALER_MHD_reply_with_error (connection,
    180                                      MHD_HTTP_INTERNAL_SERVER_ERROR,
    181                                      TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    182                                      "repeated fountain id collision");
    183 }
    184 
    185 
    186 /* end of taler-merchant-httpd_post-private-fountains.c */