merchant

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

testing_api_cmd_instance_token.c (11458B)


      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   if (NULL == tok_cmd)
    207   {
    208     GNUNET_break (0);
    209     TALER_TESTING_interpreter_fail (is);
    210     return;
    211   }
    212   if (GNUNET_OK !=
    213       TALER_TESTING_get_trait_bearer_token (tok_cmd,
    214                                             &token))
    215   {
    216     GNUNET_break (0);
    217     TALER_TESTING_interpreter_fail (is);
    218     return;
    219   }
    220   GNUNET_assert (NULL != token);
    221 
    222   GNUNET_asprintf (&authorization,
    223                    "%s: Bearer %s",
    224                    MHD_HTTP_HEADER_AUTHORIZATION,
    225                    token);
    226   GNUNET_assert (GNUNET_OK ==
    227                  GNUNET_CURL_append_header (cctx,
    228                                             authorization));
    229   GNUNET_free (authorization);
    230   TALER_TESTING_interpreter_next (is);
    231 }
    232 
    233 
    234 /**
    235  * Run the "token /instances/$ID" CMD.
    236  *
    237  * @param cls closure.
    238  * @param cmd command being run now.
    239  * @param is interpreter state.
    240  */
    241 static void
    242 token_instance_run (void *cls,
    243                     const struct TALER_TESTING_Command *cmd,
    244                     struct TALER_TESTING_Interpreter *is)
    245 {
    246   struct TokenInstanceState *tis = cls;
    247 
    248   tis->is = is;
    249   if (GNUNET_NO == tis->is_delete)
    250   {
    251     tis->itph = TALER_MERCHANT_post_private_token_create (
    252       TALER_TESTING_interpreter_get_context (is),
    253       tis->merchant_url,
    254       tis->instance_id,
    255       tis->scope);
    256     GNUNET_assert (GNUNET_OK ==
    257                    TALER_MERCHANT_post_private_token_set_options (
    258                      tis->itph,
    259                      TALER_MERCHANT_post_private_token_option_duration (
    260                        tis->duration),
    261                      TALER_MERCHANT_post_private_token_option_refreshable (
    262                        tis->refreshable)));
    263     {
    264       enum TALER_ErrorCode ec;
    265 
    266       ec = TALER_MERCHANT_post_private_token_start (
    267         tis->itph,
    268         &token_instance_post_cb,
    269         tis);
    270       GNUNET_assert (TALER_EC_NONE == ec);
    271     }
    272   }
    273   else
    274   {
    275     tis->itdh = TALER_MERCHANT_delete_private_token_create (
    276       TALER_TESTING_interpreter_get_context (is),
    277       tis->merchant_url,
    278       tis->instance_id);
    279     {
    280       enum TALER_ErrorCode ec;
    281 
    282       ec = TALER_MERCHANT_delete_private_token_start (
    283         tis->itdh,
    284         &token_instance_delete_cb,
    285         tis);
    286       GNUNET_assert (TALER_EC_NONE == ec);
    287     }
    288   }
    289 }
    290 
    291 
    292 /**
    293  * Free the state of a "POST instance token" CMD, and possibly
    294  * cancel a pending operation thereof.
    295  *
    296  * @param cls closure.
    297  * @param cmd command being run.
    298  */
    299 static void
    300 token_instance_cleanup (void *cls,
    301                         const struct TALER_TESTING_Command *cmd)
    302 {
    303   struct TokenInstanceState *tis = cls;
    304 
    305   if (NULL != tis->itph)
    306   {
    307     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    308                 "POST /instance/$ID/token operation did not complete\n");
    309     TALER_MERCHANT_post_private_token_cancel (tis->itph);
    310   }
    311   if (NULL != tis->itdh)
    312   {
    313     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    314                 "DELETE /instance/$ID/token operation did not complete\n");
    315     TALER_MERCHANT_delete_private_token_cancel (tis->itdh);
    316   }
    317   GNUNET_free (tis->token);
    318   GNUNET_free (tis);
    319 }
    320 
    321 
    322 /**
    323  * Offer internal data to other commands.
    324  *
    325  * @param cls closure
    326  * @param[out] ret result (could be anything)
    327  * @param trait name of the trait
    328  * @param index index number of the object to extract.
    329  * @return #GNUNET_OK on success
    330  */
    331 static enum GNUNET_GenericReturnValue
    332 token_instance_traits (void *cls,
    333                        const void **ret,
    334                        const char *trait,
    335                        unsigned int index)
    336 {
    337   struct TokenInstanceState *ais = cls;
    338   struct TALER_TESTING_Trait traits[] = {
    339     TALER_TESTING_make_trait_bearer_token (ais->token),
    340     TALER_TESTING_trait_end ()
    341   };
    342 
    343   return TALER_TESTING_get_trait (traits,
    344                                   ret,
    345                                   trait,
    346                                   index);
    347 }
    348 
    349 
    350 struct TALER_TESTING_Command
    351 TALER_TESTING_cmd_merchant_delete_instance_token (const char *label,
    352                                                   const char *merchant_url,
    353                                                   const char *instance_id,
    354                                                   unsigned int http_status)
    355 {
    356   struct TokenInstanceState *tis;
    357 
    358   tis = GNUNET_new (struct TokenInstanceState);
    359   tis->merchant_url = merchant_url;
    360   tis->instance_id = instance_id;
    361   tis->is_delete = GNUNET_YES;
    362   tis->http_status = http_status;
    363 
    364   {
    365     struct TALER_TESTING_Command cmd = {
    366       .cls = tis,
    367       .label = label,
    368       .run = &token_instance_run,
    369       .cleanup = &token_instance_cleanup,
    370       .traits = &token_instance_traits
    371     };
    372 
    373     return cmd;
    374   }
    375 }
    376 
    377 
    378 struct TALER_TESTING_Command
    379 TALER_TESTING_cmd_merchant_set_instance_token (const char *label,
    380                                                const char *token_job_label)
    381 {
    382   {
    383     struct TALER_TESTING_Command cmd = {
    384       .cls = (void*) token_job_label, // FIXME scope
    385       .label = label,
    386       .run = &set_token_instance_run,
    387       .cleanup = NULL,
    388       .traits = NULL
    389     };
    390 
    391     return cmd;
    392   }
    393 }
    394 
    395 
    396 struct TALER_TESTING_Command
    397 TALER_TESTING_cmd_merchant_post_instance_token (const char *label,
    398                                                 const char *merchant_url,
    399                                                 const char *instance_id,
    400                                                 const char *scope,
    401                                                 struct GNUNET_TIME_Relative
    402                                                 duration,
    403                                                 bool refreshable,
    404                                                 unsigned int http_status)
    405 {
    406   struct TokenInstanceState *tis;
    407 
    408   tis = GNUNET_new (struct TokenInstanceState);
    409   tis->merchant_url = merchant_url;
    410   tis->instance_id = instance_id;
    411   tis->scope = scope;
    412   tis->duration = duration;
    413   tis->refreshable = refreshable;
    414   tis->is_delete = GNUNET_NO;
    415   tis->http_status = http_status;
    416 
    417   {
    418     struct TALER_TESTING_Command cmd = {
    419       .cls = tis,
    420       .label = label,
    421       .run = &token_instance_run,
    422       .cleanup = &token_instance_cleanup,
    423       .traits = &token_instance_traits
    424     };
    425 
    426     return cmd;
    427   }
    428 }
    429 
    430 
    431 /* end of testing_api_cmd_token_instance.c */