merchant

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

testing_api_cmd_instance_token.c (11214B)


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