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

Generated by: LCOV version 2.0-1