merchant

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

testing_api_cmd_instance_token.c (11063B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 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 General Public License as
      7   published by the Free Software Foundation; either version 3, or
      8   (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, see
     17   <http://www.gnu.org/licenses/>
     18 */
     19 /**
     20  * @file testing_api_cmd_instance_token.c
     21  * @brief command to test /private/token POSTing
     22  * @author Martin Schanzenbach
     23  */
     24 #include "taler/platform.h"
     25 #include <taler/taler_exchange_service.h>
     26 #include <taler/taler_testing_lib.h>
     27 #include "taler/taler_merchant_service.h"
     28 #include "taler/taler_merchant_testing_lib.h"
     29 #include <taler/taler-merchant/delete-private-tokens-SERIAL.h>
     30 #include <taler/taler-merchant/post-private-token.h>
     31 
     32 
     33 /**
     34  * State of a "POST /instances/$ID/private/token" CMD.
     35  */
     36 struct TokenInstanceState
     37 {
     38 
     39   /**
     40    * Handle for a "POST token" request.
     41    */
     42   struct TALER_MERCHANT_PostPrivateTokenHandle *itph;
     43 
     44   /**
     45    * Handle for a "DELETE token" request.
     46    */
     47   struct TALER_MERCHANT_DeletePrivateTokenHandle *itdh;
     48 
     49   /**
     50    * The interpreter state.
     51    */
     52   struct TALER_TESTING_Interpreter *is;
     53 
     54   /**
     55    * Base URL of the merchant serving the request.
     56    */
     57   const char *merchant_url;
     58 
     59   /**
     60    * ID of the instance to run GET for.
     61    */
     62   const char *instance_id;
     63 
     64   /**
     65    * The received token (if any).
     66    */
     67   char *token;
     68 
     69   /**
     70    * Desired scope. Can be NULL
     71    */
     72   const char *scope;
     73 
     74   /**
     75    * Desired duration.
     76    */
     77   struct GNUNET_TIME_Relative duration;
     78 
     79   /**
     80    * Refreshable?
     81    */
     82   bool refreshable;
     83 
     84   /**
     85    * Expected HTTP response code.
     86    */
     87   unsigned int http_status;
     88 
     89   /**
     90    * DELETE or POST.
     91    */
     92   unsigned int is_delete;
     93 
     94 };
     95 
     96 /**
     97  * Callback for a POST /instances/$ID/private/token operation.
     98  *
     99  * @param cls closure for this function
    100  * @param ptr response being processed
    101  */
    102 static void
    103 token_instance_post_cb (void *cls,
    104                         const struct TALER_MERCHANT_PostPrivateTokenResponse *
    105                         ptr)
    106 {
    107   struct TokenInstanceState *tis = cls;
    108 
    109   tis->itph = NULL;
    110   if (tis->http_status != ptr->hr.http_status)
    111   {
    112     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    113                 "Unexpected response code %u (%d) to command %s\n",
    114                 ptr->hr.http_status,
    115                 (int) ptr->hr.ec,
    116                 TALER_TESTING_interpreter_get_current_label (tis->is));
    117     TALER_TESTING_interpreter_fail (tis->is);
    118     return;
    119   }
    120   switch (ptr->hr.http_status)
    121   {
    122   case MHD_HTTP_OK:
    123     if (NULL != ptr->details.ok.access_token)
    124       tis->token = GNUNET_strdup (ptr->details.ok.access_token);
    125     break;
    126   case MHD_HTTP_BAD_REQUEST:
    127     /* likely invalid auth value, we do not check client-side */
    128     break;
    129   case MHD_HTTP_FORBIDDEN:
    130     break;
    131   default:
    132     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    133                 "Unhandled HTTP status %u (%d) returned from /private/token operation.\n",
    134                 ptr->hr.http_status,
    135                 ptr->hr.ec);
    136   }
    137   TALER_TESTING_interpreter_next (tis->is);
    138 }
    139 
    140 
    141 /**
    142  * Callback for a DELETE /private/tokens/$SERIAL operation.
    143  *
    144  * @param cls closure for this function
    145  * @param dtr response being processed
    146  */
    147 static void
    148 token_instance_delete_cb (
    149   void *cls,
    150   const struct TALER_MERCHANT_DeletePrivateTokenResponse *dtr)
    151 {
    152   struct TokenInstanceState *tis = cls;
    153 
    154   tis->itdh = NULL;
    155   if (tis->http_status != dtr->hr.http_status)
    156   {
    157     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    158                 "Unexpected response code %u (%d) to command %s\n",
    159                 dtr->hr.http_status,
    160                 (int) dtr->hr.ec,
    161                 TALER_TESTING_interpreter_get_current_label (tis->is));
    162     TALER_TESTING_interpreter_fail (tis->is);
    163     return;
    164   }
    165   switch (dtr->hr.http_status)
    166   {
    167   case MHD_HTTP_NO_CONTENT:
    168     break;
    169   case MHD_HTTP_FORBIDDEN:
    170     break;
    171   default:
    172     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    173                 "Unhandled HTTP status %u (%d) returned from DELETE /private/tokens operation.\n",
    174                 dtr->hr.http_status,
    175                 dtr->hr.ec);
    176   }
    177   TALER_TESTING_interpreter_next (tis->is);
    178 }
    179 
    180 
    181 /**
    182  * set a token
    183  *
    184  *
    185  * @param cls closure.
    186  * @param cmd command being run now.
    187  * @param is interpreter state.
    188  */
    189 static void
    190 set_token_instance_run (void *cls,
    191                         const struct TALER_TESTING_Command *cmd,
    192                         struct TALER_TESTING_Interpreter *is)
    193 {
    194   const char *token_job_label = cls;
    195   const char *token;
    196   const struct TALER_TESTING_Command *tok_cmd;
    197   struct GNUNET_CURL_Context *cctx;
    198   char *authorization;
    199 
    200   cctx = TALER_TESTING_interpreter_get_context (is);
    201   GNUNET_assert (NULL != cctx);
    202   tok_cmd = TALER_TESTING_interpreter_lookup_command (
    203     is,
    204     token_job_label);
    205   TALER_TESTING_get_trait_bearer_token (tok_cmd,
    206                                         &token);
    207   GNUNET_assert (NULL != token);
    208 
    209   GNUNET_asprintf (&authorization,
    210                    "%s: Bearer %s",
    211                    MHD_HTTP_HEADER_AUTHORIZATION,
    212                    token);
    213   GNUNET_assert (GNUNET_OK ==
    214                  GNUNET_CURL_append_header (cctx,
    215                                             authorization));
    216   GNUNET_free (authorization);
    217   TALER_TESTING_interpreter_next (is);
    218 }
    219 
    220 
    221 /**
    222  * Run the "token /instances/$ID" CMD.
    223  *
    224  * @param cls closure.
    225  * @param cmd command being run now.
    226  * @param is interpreter state.
    227  */
    228 static void
    229 token_instance_run (void *cls,
    230                     const struct TALER_TESTING_Command *cmd,
    231                     struct TALER_TESTING_Interpreter *is)
    232 {
    233   struct TokenInstanceState *tis = cls;
    234 
    235   tis->is = is;
    236   if (GNUNET_NO == tis->is_delete)
    237   {
    238     tis->itph = TALER_MERCHANT_post_private_token_create (
    239       TALER_TESTING_interpreter_get_context (is),
    240       tis->merchant_url,
    241       tis->instance_id,
    242       tis->scope);
    243     GNUNET_assert (GNUNET_OK ==
    244                    TALER_MERCHANT_post_private_token_set_options (
    245                      tis->itph,
    246                      TALER_MERCHANT_post_private_token_option_duration (
    247                        tis->duration),
    248                      TALER_MERCHANT_post_private_token_option_refreshable (
    249                        tis->refreshable)));
    250     {
    251       enum TALER_ErrorCode ec;
    252 
    253       ec = TALER_MERCHANT_post_private_token_start (
    254         tis->itph,
    255         &token_instance_post_cb,
    256         tis);
    257       GNUNET_assert (TALER_EC_NONE == ec);
    258     }
    259   }
    260   else
    261   {
    262     tis->itdh = TALER_MERCHANT_delete_private_token_create (
    263       TALER_TESTING_interpreter_get_context (is),
    264       tis->merchant_url,
    265       tis->instance_id);
    266     {
    267       enum TALER_ErrorCode ec;
    268 
    269       ec = TALER_MERCHANT_delete_private_token_start (
    270         tis->itdh,
    271         &token_instance_delete_cb,
    272         tis);
    273       GNUNET_assert (TALER_EC_NONE == ec);
    274     }
    275   }
    276 }
    277 
    278 
    279 /**
    280  * Free the state of a "POST instance token" CMD, and possibly
    281  * cancel a pending operation thereof.
    282  *
    283  * @param cls closure.
    284  * @param cmd command being run.
    285  */
    286 static void
    287 token_instance_cleanup (void *cls,
    288                         const struct TALER_TESTING_Command *cmd)
    289 {
    290   struct TokenInstanceState *tis = cls;
    291 
    292   if (NULL != tis->itph)
    293   {
    294     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    295                 "POST /instance/$ID/token operation did not complete\n");
    296     TALER_MERCHANT_post_private_token_cancel (tis->itph);
    297   }
    298   if (NULL != tis->itdh)
    299   {
    300     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    301                 "DELETE /instance/$ID/token operation did not complete\n");
    302     TALER_MERCHANT_delete_private_token_cancel (tis->itdh);
    303   }
    304   GNUNET_free (tis);
    305 }
    306 
    307 
    308 /**
    309  * Offer internal data to other commands.
    310  *
    311  * @param cls closure
    312  * @param[out] ret result (could be anything)
    313  * @param trait name of the trait
    314  * @param index index number of the object to extract.
    315  * @return #GNUNET_OK on success
    316  */
    317 static enum GNUNET_GenericReturnValue
    318 token_instance_traits (void *cls,
    319                        const void **ret,
    320                        const char *trait,
    321                        unsigned int index)
    322 {
    323   struct TokenInstanceState *ais = cls;
    324   struct TALER_TESTING_Trait traits[] = {
    325     TALER_TESTING_make_trait_bearer_token (ais->token),
    326     TALER_TESTING_trait_end ()
    327   };
    328 
    329   return TALER_TESTING_get_trait (traits,
    330                                   ret,
    331                                   trait,
    332                                   index);
    333 }
    334 
    335 
    336 struct TALER_TESTING_Command
    337 TALER_TESTING_cmd_merchant_delete_instance_token (const char *label,
    338                                                   const char *merchant_url,
    339                                                   const char *instance_id,
    340                                                   unsigned int http_status)
    341 {
    342   struct TokenInstanceState *tis;
    343 
    344   tis = GNUNET_new (struct TokenInstanceState);
    345   tis->merchant_url = merchant_url;
    346   tis->instance_id = instance_id;
    347   tis->is_delete = GNUNET_YES;
    348   tis->http_status = http_status;
    349 
    350   {
    351     struct TALER_TESTING_Command cmd = {
    352       .cls = tis,
    353       .label = label,
    354       .run = &token_instance_run,
    355       .cleanup = &token_instance_cleanup,
    356       .traits = &token_instance_traits
    357     };
    358 
    359     return cmd;
    360   }
    361 }
    362 
    363 
    364 struct TALER_TESTING_Command
    365 TALER_TESTING_cmd_merchant_set_instance_token (const char *label,
    366                                                const char *token_job_label)
    367 {
    368   {
    369     struct TALER_TESTING_Command cmd = {
    370       .cls = (void*) token_job_label, // FIXME scope
    371       .label = label,
    372       .run = &set_token_instance_run,
    373       .cleanup = NULL,
    374       .traits = NULL
    375     };
    376 
    377     return cmd;
    378   }
    379 }
    380 
    381 
    382 struct TALER_TESTING_Command
    383 TALER_TESTING_cmd_merchant_post_instance_token (const char *label,
    384                                                 const char *merchant_url,
    385                                                 const char *instance_id,
    386                                                 const char *scope,
    387                                                 struct GNUNET_TIME_Relative
    388                                                 duration,
    389                                                 bool refreshable,
    390                                                 unsigned int http_status)
    391 {
    392   struct TokenInstanceState *tis;
    393 
    394   tis = GNUNET_new (struct TokenInstanceState);
    395   tis->merchant_url = merchant_url;
    396   tis->instance_id = instance_id;
    397   tis->scope = scope;
    398   tis->duration = duration;
    399   tis->refreshable = refreshable;
    400   tis->is_delete = GNUNET_NO;
    401   tis->http_status = http_status;
    402 
    403   {
    404     struct TALER_TESTING_Command cmd = {
    405       .cls = tis,
    406       .label = label,
    407       .run = &token_instance_run,
    408       .cleanup = &token_instance_cleanup,
    409       .traits = &token_instance_traits
    410     };
    411 
    412     return cmd;
    413   }
    414 }
    415 
    416 
    417 /* end of testing_api_cmd_token_instance.c */