LCOV - code coverage report
Current view: top level - backend - taler-merchant-httpd_private-post-instances.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 47.2 % 246 116
Test Date: 2026-01-01 16:44:56 Functions: 66.7 % 3 2

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   (C) 2020-2025 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 taler-merchant-httpd_private-post-instances.c
      22              :  * @brief implementing POST /instances request handling
      23              :  * @author Christian Grothoff
      24              :  */
      25              : #include "platform.h"
      26              : #include "taler-merchant-httpd_private-post-instances.h"
      27              : #include "taler-merchant-httpd_helper.h"
      28              : #include "taler-merchant-httpd.h"
      29              : #include "taler-merchant-httpd_auth.h"
      30              : #include "taler-merchant-httpd_mfa.h"
      31              : #include "taler_merchant_bank_lib.h"
      32              : #include <taler/taler_dbevents.h>
      33              : #include <taler/taler_json_lib.h>
      34              : #include <regex.h>
      35              : 
      36              : /**
      37              :  * How often do we retry the simple INSERT database transaction?
      38              :  */
      39              : #define MAX_RETRIES 3
      40              : 
      41              : 
      42              : /**
      43              :  * Generate an instance, given its configuration.
      44              :  *
      45              :  * @param rh context of the handler
      46              :  * @param connection the MHD connection to handle
      47              :  * @param[in,out] hc context with further information about the request
      48              :  * @param login_token_expiration set to how long a login token validity
      49              :  *   should be, use zero if no login token should be created
      50              :  * @param validation_needed true if self-provisioned and
      51              :  *   email/phone registration is required before the
      52              :  *   instance can become fully active
      53              :  * @return MHD result code
      54              :  */
      55              : static MHD_RESULT
      56           33 : post_instances (const struct TMH_RequestHandler *rh,
      57              :                 struct MHD_Connection *connection,
      58              :                 struct TMH_HandlerContext *hc,
      59              :                 struct GNUNET_TIME_Relative login_token_expiration,
      60              :                 bool validation_needed)
      61              : {
      62           33 :   struct TALER_MERCHANTDB_InstanceSettings is = { 0 };
      63              :   struct TALER_MERCHANTDB_InstanceAuthSettings ias;
      64           33 :   const char *auth_password = NULL;
      65           33 :   struct TMH_WireMethod *wm_head = NULL;
      66           33 :   struct TMH_WireMethod *wm_tail = NULL;
      67              :   const json_t *jauth;
      68              :   bool no_pay_delay;
      69              :   bool no_refund_delay;
      70              :   bool no_transfer_delay;
      71              :   bool no_rounding_interval;
      72              :   struct GNUNET_JSON_Specification spec[] = {
      73           33 :     GNUNET_JSON_spec_string ("id",
      74              :                              (const char **) &is.id),
      75           33 :     GNUNET_JSON_spec_string ("name",
      76              :                              (const char **) &is.name),
      77           33 :     GNUNET_JSON_spec_mark_optional (
      78              :       GNUNET_JSON_spec_string ("email",
      79              :                                (const char **) &is.email),
      80              :       NULL),
      81           33 :     GNUNET_JSON_spec_mark_optional (
      82              :       GNUNET_JSON_spec_string ("phone_number",
      83              :                                (const char **) &is.phone),
      84              :       NULL),
      85           33 :     GNUNET_JSON_spec_mark_optional (
      86              :       GNUNET_JSON_spec_string ("website",
      87              :                                (const char **) &is.website),
      88              :       NULL),
      89           33 :     GNUNET_JSON_spec_mark_optional (
      90              :       GNUNET_JSON_spec_string ("logo",
      91              :                                (const char **) &is.logo),
      92              :       NULL),
      93           33 :     GNUNET_JSON_spec_object_const ("auth",
      94              :                                    &jauth),
      95           33 :     GNUNET_JSON_spec_json ("address",
      96              :                            &is.address),
      97           33 :     GNUNET_JSON_spec_json ("jurisdiction",
      98              :                            &is.jurisdiction),
      99           33 :     GNUNET_JSON_spec_bool ("use_stefan",
     100              :                            &is.use_stefan),
     101           33 :     GNUNET_JSON_spec_mark_optional (
     102              :       GNUNET_JSON_spec_relative_time ("default_pay_delay",
     103              :                                       &is.default_pay_delay),
     104              :       &no_pay_delay),
     105           33 :     GNUNET_JSON_spec_mark_optional (
     106              :       GNUNET_JSON_spec_relative_time ("default_refund_delay",
     107              :                                       &is.default_refund_delay),
     108              :       &no_refund_delay),
     109           33 :     GNUNET_JSON_spec_mark_optional (
     110              :       GNUNET_JSON_spec_relative_time ("default_wire_transfer_delay",
     111              :                                       &is.default_wire_transfer_delay),
     112              :       &no_transfer_delay),
     113           33 :     GNUNET_JSON_spec_mark_optional (
     114              :       GNUNET_JSON_spec_time_rounder_interval (
     115              :         "default_wire_transfer_rounding_interval",
     116              :         &is.default_wire_transfer_rounding_interval),
     117              :       &no_rounding_interval),
     118           33 :     GNUNET_JSON_spec_end ()
     119              :   };
     120              : 
     121              :   {
     122              :     enum GNUNET_GenericReturnValue res;
     123              : 
     124           33 :     res = TALER_MHD_parse_json_data (connection,
     125           33 :                                      hc->request_body,
     126              :                                      spec);
     127           33 :     if (GNUNET_OK != res)
     128              :       return (GNUNET_NO == res)
     129              :              ? MHD_YES
     130            0 :              : MHD_NO;
     131              :   }
     132           33 :   if (no_pay_delay)
     133            0 :     is.default_pay_delay = TMH_default_pay_delay;
     134           33 :   if (no_refund_delay)
     135           14 :     is.default_refund_delay = TMH_default_refund_delay;
     136           33 :   if (no_transfer_delay)
     137            0 :     is.default_wire_transfer_delay = TMH_default_wire_transfer_delay;
     138           33 :   if (no_rounding_interval)
     139              :     is.default_wire_transfer_rounding_interval
     140           14 :       = TMH_default_wire_transfer_rounding_interval;
     141           33 :   if (GNUNET_TIME_relative_is_forever (is.default_pay_delay))
     142              :   {
     143            0 :     GNUNET_break_op (0);
     144            0 :     GNUNET_JSON_parse_free (spec);
     145            0 :     return TALER_MHD_reply_with_error (connection,
     146              :                                        MHD_HTTP_BAD_REQUEST,
     147              :                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
     148              :                                        "default_pay_delay");
     149              :   }
     150           33 :   if (GNUNET_TIME_relative_is_forever (is.default_refund_delay))
     151              :   {
     152            0 :     GNUNET_break_op (0);
     153            0 :     GNUNET_JSON_parse_free (spec);
     154            0 :     return TALER_MHD_reply_with_error (connection,
     155              :                                        MHD_HTTP_BAD_REQUEST,
     156              :                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
     157              :                                        "default_refund_delay");
     158              :   }
     159           33 :   if (GNUNET_TIME_relative_is_forever (is.default_wire_transfer_delay))
     160              :   {
     161            0 :     GNUNET_break_op (0);
     162            0 :     GNUNET_JSON_parse_free (spec);
     163            0 :     return TALER_MHD_reply_with_error (connection,
     164              :                                        MHD_HTTP_BAD_REQUEST,
     165              :                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
     166              :                                        "default_wire_transfer_delay");
     167              :   }
     168              : 
     169              :   {
     170              :     enum GNUNET_GenericReturnValue ret;
     171              : 
     172           33 :     ret = TMH_check_auth_config (connection,
     173              :                                  jauth,
     174              :                                  &auth_password);
     175           33 :     if (GNUNET_OK != ret)
     176              :     {
     177            0 :       GNUNET_JSON_parse_free (spec);
     178            0 :       return (GNUNET_NO == ret) ? MHD_YES : MHD_NO;
     179              :     }
     180              :   }
     181              : 
     182              :   /* check 'id' well-formed */
     183              :   {
     184              :     static bool once;
     185              :     static regex_t reg;
     186           33 :     bool id_wellformed = true;
     187              : 
     188           33 :     if (! once)
     189              :     {
     190           15 :       once = true;
     191           15 :       GNUNET_assert (0 ==
     192              :                      regcomp (&reg,
     193              :                               "^[A-Za-z0-9][A-Za-z0-9_.@-]+$",
     194              :                               REG_EXTENDED));
     195              :     }
     196              : 
     197           33 :     if (0 != regexec (&reg,
     198           33 :                       is.id,
     199              :                       0, NULL, 0))
     200            0 :       id_wellformed = false;
     201           33 :     if (! id_wellformed)
     202              :     {
     203            0 :       GNUNET_JSON_parse_free (spec);
     204            0 :       return TALER_MHD_reply_with_error (connection,
     205              :                                          MHD_HTTP_BAD_REQUEST,
     206              :                                          TALER_EC_GENERIC_PARAMETER_MALFORMED,
     207              :                                          "id");
     208              :     }
     209              :   }
     210              : 
     211           33 :   if (! TMH_location_object_valid (is.address))
     212              :   {
     213            0 :     GNUNET_break_op (0);
     214            0 :     GNUNET_JSON_parse_free (spec);
     215            0 :     return TALER_MHD_reply_with_error (connection,
     216              :                                        MHD_HTTP_BAD_REQUEST,
     217              :                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
     218              :                                        "address");
     219              :   }
     220              : 
     221           33 :   if (! TMH_location_object_valid (is.jurisdiction))
     222              :   {
     223            0 :     GNUNET_break_op (0);
     224            0 :     GNUNET_JSON_parse_free (spec);
     225            0 :     return TALER_MHD_reply_with_error (connection,
     226              :                                        MHD_HTTP_BAD_REQUEST,
     227              :                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
     228              :                                        "jurisdiction");
     229              :   }
     230              : 
     231           33 :   if ( (NULL != is.logo) &&
     232            0 :        (! TALER_MERCHANT_image_data_url_valid (is.logo)) )
     233              :   {
     234            0 :     GNUNET_break_op (0);
     235            0 :     GNUNET_JSON_parse_free (spec);
     236            0 :     return TALER_MHD_reply_with_error (connection,
     237              :                                        MHD_HTTP_BAD_REQUEST,
     238              :                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
     239              :                                        "logo");
     240              :   }
     241              : 
     242              :   {
     243              :     /* Test if an instance of this id is known */
     244              :     struct TMH_MerchantInstance *mi;
     245              : 
     246           33 :     mi = TMH_lookup_instance (is.id);
     247           33 :     if (NULL != mi)
     248              :     {
     249            2 :       if (mi->deleted)
     250              :       {
     251            0 :         GNUNET_JSON_parse_free (spec);
     252            0 :         return TALER_MHD_reply_with_error (connection,
     253              :                                            MHD_HTTP_CONFLICT,
     254              :                                            TALER_EC_MERCHANT_PRIVATE_POST_INSTANCES_PURGE_REQUIRED,
     255            0 :                                            is.id);
     256              :       }
     257              :       /* Check for idempotency */
     258            2 :       if ( (0 == strcmp (mi->settings.id,
     259            2 :                          is.id)) &&
     260            2 :            (0 == strcmp (mi->settings.name,
     261            2 :                          is.name)) &&
     262            2 :            ((mi->settings.email == is.email) ||
     263            0 :             (NULL != is.email && NULL != mi->settings.email &&
     264            0 :              0 == strcmp (mi->settings.email,
     265            0 :                           is.email))) &&
     266            2 :            ((mi->settings.website == is.website) ||
     267            0 :             (NULL != is.website && NULL != mi->settings.website &&
     268            0 :              0 == strcmp (mi->settings.website,
     269            0 :                           is.website))) &&
     270            2 :            ((mi->settings.logo == is.logo) ||
     271            0 :             (NULL != is.logo && NULL != mi->settings.logo &&
     272            0 :              0 == strcmp (mi->settings.logo,
     273            0 :                           is.logo))) &&
     274            2 :            ( ( (NULL != auth_password) &&
     275              :                (GNUNET_OK ==
     276            0 :                 TMH_check_auth (auth_password,
     277              :                                 &mi->auth.auth_salt,
     278            2 :                                 &mi->auth.auth_hash)) ) ||
     279            4 :              ( (NULL == auth_password) &&
     280              :                (GNUNET_YES ==
     281            4 :                 GNUNET_is_zero (&mi->auth.auth_hash))) ) &&
     282            2 :            (1 == json_equal (mi->settings.address,
     283            4 :                              is.address)) &&
     284            2 :            (1 == json_equal (mi->settings.jurisdiction,
     285            2 :                              is.jurisdiction)) &&
     286            2 :            (mi->settings.use_stefan == is.use_stefan) &&
     287            2 :            (GNUNET_TIME_relative_cmp (mi->settings.default_wire_transfer_delay,
     288              :                                       ==,
     289            2 :                                       is.default_wire_transfer_delay)) &&
     290            2 :            (GNUNET_TIME_relative_cmp (mi->settings.default_pay_delay,
     291              :                                       ==,
     292            2 :                                       is.default_pay_delay)) &&
     293            2 :            (GNUNET_TIME_relative_cmp (mi->settings.default_refund_delay,
     294              :                                       ==,
     295              :                                       is.default_refund_delay)) )
     296              :       {
     297            2 :         GNUNET_JSON_parse_free (spec);
     298            2 :         return TALER_MHD_reply_static (connection,
     299              :                                        MHD_HTTP_NO_CONTENT,
     300              :                                        NULL,
     301              :                                        NULL,
     302              :                                        0);
     303              :       }
     304            0 :       GNUNET_JSON_parse_free (spec);
     305            0 :       return TALER_MHD_reply_with_error (connection,
     306              :                                          MHD_HTTP_CONFLICT,
     307              :                                          TALER_EC_MERCHANT_PRIVATE_POST_INSTANCES_ALREADY_EXISTS,
     308            0 :                                          is.id);
     309              :     }
     310              :   }
     311              : 
     312              :   /* Check MFA is satisfied */
     313           31 :   if (validation_needed)
     314              :   {
     315            0 :     enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR;
     316              : 
     317            0 :     if ( (0 != (TEH_TCS_SMS & TEH_mandatory_tan_channels)) &&
     318            0 :          (NULL == is.phone) )
     319              :     {
     320            0 :       GNUNET_break_op (0);
     321            0 :       GNUNET_JSON_parse_free (spec);
     322            0 :       return TALER_MHD_reply_with_error (connection,
     323              :                                          MHD_HTTP_BAD_REQUEST,
     324              :                                          TALER_EC_GENERIC_PARAMETER_MISSING,
     325              :                                          "phone_number");
     326              : 
     327              :     }
     328            0 :     if ( (0 != (TEH_TCS_EMAIL & TEH_mandatory_tan_channels)) &&
     329            0 :          (NULL == is.email) )
     330              :     {
     331            0 :       GNUNET_break_op (0);
     332            0 :       GNUNET_JSON_parse_free (spec);
     333            0 :       return TALER_MHD_reply_with_error (connection,
     334              :                                          MHD_HTTP_BAD_REQUEST,
     335              :                                          TALER_EC_GENERIC_PARAMETER_MISSING,
     336              :                                          "email");
     337              :     }
     338            0 :     switch (TEH_mandatory_tan_channels)
     339              :     {
     340            0 :     case TEH_TCS_NONE:
     341            0 :       GNUNET_assert (0);
     342              :       ret = GNUNET_OK;
     343              :       break;
     344            0 :     case TEH_TCS_SMS:
     345            0 :       is.phone_validated = true;
     346            0 :       ret = TMH_mfa_challenges_do (hc,
     347              :                                    TALER_MERCHANT_MFA_CO_INSTANCE_PROVISION,
     348              :                                    true,
     349              :                                    TALER_MERCHANT_MFA_CHANNEL_SMS,
     350              :                                    is.phone,
     351              :                                    TALER_MERCHANT_MFA_CHANNEL_NONE);
     352            0 :       break;
     353            0 :     case TEH_TCS_EMAIL:
     354            0 :       is.email_validated = true;
     355            0 :       ret = TMH_mfa_challenges_do (hc,
     356              :                                    TALER_MERCHANT_MFA_CO_INSTANCE_PROVISION,
     357              :                                    true,
     358              :                                    TALER_MERCHANT_MFA_CHANNEL_EMAIL,
     359              :                                    is.email,
     360              :                                    TALER_MERCHANT_MFA_CHANNEL_NONE);
     361            0 :       break;
     362            0 :     case TEH_TCS_EMAIL_AND_SMS:
     363            0 :       is.phone_validated = true;
     364            0 :       is.email_validated = true;
     365            0 :       ret = TMH_mfa_challenges_do (hc,
     366              :                                    TALER_MERCHANT_MFA_CO_INSTANCE_PROVISION,
     367              :                                    true,
     368              :                                    TALER_MERCHANT_MFA_CHANNEL_SMS,
     369              :                                    is.phone,
     370              :                                    TALER_MERCHANT_MFA_CHANNEL_EMAIL,
     371              :                                    is.email,
     372              :                                    TALER_MERCHANT_MFA_CHANNEL_NONE);
     373            0 :       break;
     374              :     }
     375            0 :     if (GNUNET_OK != ret)
     376              :     {
     377            0 :       GNUNET_JSON_parse_free (spec);
     378              :       return (GNUNET_NO == ret)
     379              :         ? MHD_YES
     380            0 :         : MHD_NO;
     381              :     }
     382              :   }
     383              : 
     384              :   /* handle authentication token setup */
     385           31 :   if (NULL == auth_password)
     386              :   {
     387           25 :     memset (&ias.auth_salt,
     388              :             0,
     389              :             sizeof (ias.auth_salt));
     390           25 :     memset (&ias.auth_hash,
     391              :             0,
     392              :             sizeof (ias.auth_hash));
     393              :   }
     394              :   else
     395              :   {
     396              :     /* Sets 'auth_salt' and 'auth_hash' */
     397            6 :     TMH_compute_auth (auth_password,
     398              :                       &ias.auth_salt,
     399              :                       &ias.auth_hash);
     400              :   }
     401              : 
     402              :   /* create in-memory data structure */
     403              :   {
     404              :     struct TMH_MerchantInstance *mi;
     405              :     enum GNUNET_DB_QueryStatus qs;
     406              : 
     407           31 :     mi = GNUNET_new (struct TMH_MerchantInstance);
     408           31 :     mi->wm_head = wm_head;
     409           31 :     mi->wm_tail = wm_tail;
     410           31 :     mi->settings = is;
     411           31 :     mi->settings.address = json_incref (mi->settings.address);
     412           31 :     mi->settings.jurisdiction = json_incref (mi->settings.jurisdiction);
     413           31 :     mi->settings.id = GNUNET_strdup (is.id);
     414           31 :     mi->settings.name = GNUNET_strdup (is.name);
     415           31 :     if (NULL != is.email)
     416            0 :       mi->settings.email = GNUNET_strdup (is.email);
     417           31 :     if (NULL != is.phone)
     418            0 :       mi->settings.phone = GNUNET_strdup (is.phone);
     419           31 :     if (NULL != is.website)
     420            0 :       mi->settings.website = GNUNET_strdup (is.website);
     421           31 :     if (NULL != is.logo)
     422            0 :       mi->settings.logo = GNUNET_strdup (is.logo);
     423           31 :     mi->auth = ias;
     424           31 :     mi->validation_needed = validation_needed;
     425           31 :     GNUNET_CRYPTO_eddsa_key_create (&mi->merchant_priv.eddsa_priv);
     426           31 :     GNUNET_CRYPTO_eddsa_key_get_public (&mi->merchant_priv.eddsa_priv,
     427              :                                         &mi->merchant_pub.eddsa_pub);
     428              : 
     429           31 :     for (unsigned int i = 0; i<MAX_RETRIES; i++)
     430              :     {
     431           31 :       if (GNUNET_OK !=
     432           31 :           TMH_db->start (TMH_db->cls,
     433              :                          "post /instances"))
     434              :       {
     435            0 :         mi->rc = 1;
     436            0 :         TMH_instance_decref (mi);
     437            0 :         GNUNET_JSON_parse_free (spec);
     438            0 :         return TALER_MHD_reply_with_error (connection,
     439              :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
     440              :                                            TALER_EC_GENERIC_DB_START_FAILED,
     441              :                                            NULL);
     442              :       }
     443           31 :       qs = TMH_db->insert_instance (TMH_db->cls,
     444           31 :                                     &mi->merchant_pub,
     445           31 :                                     &mi->merchant_priv,
     446           31 :                                     &mi->settings,
     447           31 :                                     &mi->auth,
     448              :                                     validation_needed);
     449           31 :       switch (qs)
     450              :       {
     451            0 :       case GNUNET_DB_STATUS_HARD_ERROR:
     452              :         {
     453              :           MHD_RESULT ret;
     454              : 
     455            0 :           TMH_db->rollback (TMH_db->cls);
     456            0 :           GNUNET_break (0);
     457            0 :           ret = TALER_MHD_reply_with_error (connection,
     458              :                                             MHD_HTTP_INTERNAL_SERVER_ERROR,
     459              :                                             TALER_EC_GENERIC_DB_STORE_FAILED,
     460            0 :                                             is.id);
     461            0 :           mi->rc = 1;
     462            0 :           TMH_instance_decref (mi);
     463            0 :           GNUNET_JSON_parse_free (spec);
     464            0 :           return ret;
     465              :         }
     466            0 :       case GNUNET_DB_STATUS_SOFT_ERROR:
     467            0 :         goto retry;
     468            0 :       case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     469              :         {
     470              :           MHD_RESULT ret;
     471              : 
     472            0 :           TMH_db->rollback (TMH_db->cls);
     473            0 :           GNUNET_break (0);
     474            0 :           ret = TALER_MHD_reply_with_error (connection,
     475              :                                             MHD_HTTP_CONFLICT,
     476              :                                             TALER_EC_MERCHANT_PRIVATE_POST_INSTANCES_ALREADY_EXISTS,
     477            0 :                                             is.id);
     478            0 :           mi->rc = 1;
     479            0 :           TMH_instance_decref (mi);
     480            0 :           GNUNET_JSON_parse_free (spec);
     481            0 :           return ret;
     482              :         }
     483           31 :       case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     484              :         /* handled below */
     485           31 :         break;
     486              :       }
     487           31 :       qs = TMH_db->commit (TMH_db->cls);
     488           31 :       if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
     489           31 :         qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
     490            0 : retry:
     491           31 :       if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
     492           31 :         break; /* success! -- or hard failure */
     493              :     } /* for .. MAX_RETRIES */
     494           31 :     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
     495              :     {
     496            0 :       mi->rc = 1;
     497            0 :       TMH_instance_decref (mi);
     498            0 :       GNUNET_JSON_parse_free (spec);
     499            0 :       return TALER_MHD_reply_with_error (connection,
     500              :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
     501              :                                          TALER_EC_GENERIC_DB_COMMIT_FAILED,
     502              :                                          NULL);
     503              :     }
     504              :     /* Finally, also update our running process */
     505           31 :     GNUNET_assert (GNUNET_OK ==
     506              :                    TMH_add_instance (mi));
     507           31 :     TMH_reload_instances (mi->settings.id);
     508              :   }
     509           31 :   GNUNET_JSON_parse_free (spec);
     510           31 :   if (GNUNET_TIME_relative_is_zero (login_token_expiration))
     511              :   {
     512           31 :     return TALER_MHD_reply_static (connection,
     513              :                                    MHD_HTTP_NO_CONTENT,
     514              :                                    NULL,
     515              :                                    NULL,
     516              :                                    0);
     517              :   }
     518              : 
     519              :   {
     520              :     struct TALER_MERCHANTDB_LoginTokenP btoken;
     521            0 :     enum TMH_AuthScope iscope = TMH_AS_REFRESHABLE | TMH_AS_SPA;
     522              :     enum GNUNET_DB_QueryStatus qs;
     523              :     struct GNUNET_TIME_Timestamp expiration_time;
     524            0 :     bool refreshable = true;
     525              : 
     526            0 :     GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
     527              :                                 &btoken,
     528              :                                 sizeof (btoken));
     529              :     expiration_time
     530            0 :       = GNUNET_TIME_relative_to_timestamp (login_token_expiration);
     531            0 :     qs = TMH_db->insert_login_token (TMH_db->cls,
     532            0 :                                      is.id,
     533              :                                      &btoken,
     534              :                                      GNUNET_TIME_timestamp_get (),
     535              :                                      expiration_time,
     536              :                                      iscope,
     537              :                                      "login token from instance creation");
     538            0 :     switch (qs)
     539              :     {
     540            0 :     case GNUNET_DB_STATUS_HARD_ERROR:
     541              :     case GNUNET_DB_STATUS_SOFT_ERROR:
     542              :     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     543            0 :       GNUNET_break (0);
     544            0 :       return TALER_MHD_reply_with_ec (connection,
     545              :                                       TALER_EC_GENERIC_DB_STORE_FAILED,
     546              :                                       "insert_login_token");
     547            0 :     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     548            0 :       break;
     549              :     }
     550              : 
     551              :     {
     552              :       char *tok;
     553              :       MHD_RESULT ret;
     554              :       char *val;
     555              : 
     556            0 :       val = GNUNET_STRINGS_data_to_string_alloc (&btoken,
     557              :                                                  sizeof (btoken));
     558            0 :       GNUNET_asprintf (&tok,
     559              :                        RFC_8959_PREFIX "%s",
     560              :                        val);
     561            0 :       GNUNET_free (val);
     562            0 :       ret = TALER_MHD_REPLY_JSON_PACK (
     563              :         connection,
     564              :         MHD_HTTP_OK,
     565              :         GNUNET_JSON_pack_string ("access_token",
     566              :                                  tok),
     567              :         GNUNET_JSON_pack_string ("token",
     568              :                                  tok),
     569              :         GNUNET_JSON_pack_string ("scope",
     570              :                                  TMH_get_name_by_scope (iscope,
     571              :                                                         &refreshable)),
     572              :         GNUNET_JSON_pack_bool ("refreshable",
     573              :                                refreshable),
     574              :         GNUNET_JSON_pack_timestamp ("expiration",
     575              :                                     expiration_time));
     576            0 :       GNUNET_free (tok);
     577            0 :       return ret;
     578              :     }
     579              :   }
     580              : }
     581              : 
     582              : 
     583              : /**
     584              :  * Generate an instance, given its configuration.
     585              :  *
     586              :  * @param rh context of the handler
     587              :  * @param connection the MHD connection to handle
     588              :  * @param[in,out] hc context with further information about the request
     589              :  * @return MHD result code
     590              :  */
     591              : MHD_RESULT
     592           33 : TMH_private_post_instances (const struct TMH_RequestHandler *rh,
     593              :                             struct MHD_Connection *connection,
     594              :                             struct TMH_HandlerContext *hc)
     595              : {
     596           66 :   return post_instances (rh,
     597              :                          connection,
     598              :                          hc,
     599           33 :                          GNUNET_TIME_UNIT_ZERO,
     600              :                          false);
     601              : }
     602              : 
     603              : 
     604              : /**
     605              :  * Generate an instance, given its configuration.
     606              :  * Public handler to be used when self-provisioning.
     607              :  *
     608              :  * @param rh context of the handler
     609              :  * @param connection the MHD connection to handle
     610              :  * @param[in,out] hc context with further information about the request
     611              :  * @return MHD result code
     612              :  */
     613              : MHD_RESULT
     614            0 : TMH_public_post_instances (const struct TMH_RequestHandler *rh,
     615              :                            struct MHD_Connection *connection,
     616              :                            struct TMH_HandlerContext *hc)
     617              : {
     618              :   struct GNUNET_TIME_Relative expiration;
     619              : 
     620            0 :   TALER_MHD_parse_request_rel_time (connection,
     621              :                                     "token_validity_ms",
     622              :                                     &expiration);
     623            0 :   if (GNUNET_YES !=
     624              :       TMH_have_self_provisioning)
     625              :   {
     626            0 :     GNUNET_break_op (0);
     627            0 :     return TALER_MHD_reply_with_error (connection,
     628              :                                        MHD_HTTP_FORBIDDEN,
     629              :                                        TALER_EC_MERCHANT_GENERIC_UNAUTHORIZED,
     630              :                                        "Self-provisioning is not enabled");
     631              :   }
     632              : 
     633            0 :   return post_instances (rh,
     634              :                          connection,
     635              :                          hc,
     636              :                          expiration,
     637              :                          TEH_TCS_NONE !=
     638              :                          TEH_mandatory_tan_channels);
     639              : }
     640              : 
     641              : 
     642              : /* end of taler-merchant-httpd_private-post-instances.c */
        

Generated by: LCOV version 2.0-1