exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

bank_api_account_token.c (7676B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2015--2024 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   TALER; see the file COPYING.  If not, see
     15   <http://www.gnu.org/licenses/>
     16 */
     17 /**
     18  * @file bank-lib/bank_api_account_token.c
     19  * @brief Implementation of the /account/$ACC/token requests of the bank's HTTP API
     20  * @author Christian Grothoff
     21  */
     22 #include "taler/platform.h"
     23 #include "bank_api_common.h"
     24 #include <microhttpd.h> /* just for HTTP status codes */
     25 #include "taler/taler_signatures.h"
     26 #include "taler/taler_curl_lib.h"
     27 
     28 
     29 struct TALER_BANK_AccountTokenHandle
     30 {
     31 
     32   /**
     33    * The url for this request.
     34    */
     35   char *request_url;
     36 
     37   /**
     38    * POST context.
     39    */
     40   struct TALER_CURL_PostContext post_ctx;
     41 
     42   /**
     43    * Handle for the request.
     44    */
     45   struct GNUNET_CURL_Job *job;
     46 
     47   /**
     48    * Function to call with the result.
     49    */
     50   TALER_BANK_AccountTokenCallback cb;
     51 
     52   /**
     53    * Closure for @a cb.
     54    */
     55   void *cb_cls;
     56 
     57 };
     58 
     59 
     60 /**
     61  * Function called when we're done processing the
     62  * HTTP /account/$ACC/token request.
     63  *
     64  * @param cls the `struct TALER_BANK_AccountTokenHandle`
     65  * @param response_code HTTP response code, 0 on error
     66  * @param response parsed JSON result, NULL on error
     67  */
     68 static void
     69 handle_account_token_finished (void *cls,
     70                                long response_code,
     71                                const void *response)
     72 {
     73   struct TALER_BANK_AccountTokenHandle *aai = cls;
     74   const json_t *j = response;
     75   struct TALER_BANK_AccountTokenResponse ir = {
     76     .http_status = response_code,
     77     .response = response
     78   };
     79 
     80   aai->job = NULL;
     81   switch (response_code)
     82   {
     83   case 0:
     84     ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     85     break;
     86   case MHD_HTTP_OK:
     87     {
     88       struct GNUNET_JSON_Specification spec[] = {
     89         GNUNET_JSON_spec_string ("access_token",
     90                                  &ir.details.ok.access_token),
     91         GNUNET_JSON_spec_timestamp ("expiration",
     92                                     &ir.details.ok.expiration),
     93         GNUNET_JSON_spec_end ()
     94       };
     95 
     96       if (GNUNET_OK !=
     97           GNUNET_JSON_parse (j,
     98                              spec,
     99                              NULL, NULL))
    100       {
    101         GNUNET_break_op (0);
    102         ir.http_status = 0;
    103         ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    104         break;
    105       }
    106     }
    107     break;
    108   case MHD_HTTP_BAD_REQUEST:
    109     /* This should never happen, either us or the bank is buggy
    110        (or API version conflict); just pass JSON reply to the application */
    111     GNUNET_break_op (0);
    112     ir.ec = TALER_JSON_get_error_code (j);
    113     break;
    114   case MHD_HTTP_FORBIDDEN:
    115     /* Access denied */
    116     ir.ec = TALER_JSON_get_error_code (j);
    117     break;
    118   case MHD_HTTP_UNAUTHORIZED:
    119     /* Nothing really to verify, bank says the password is invalid; we should
    120        pass the JSON reply to the application */
    121     ir.ec = TALER_JSON_get_error_code (j);
    122     break;
    123   case MHD_HTTP_NOT_FOUND:
    124     /* Nothing really to verify, maybe account really does not exist.
    125        We should pass the JSON reply to the application */
    126     ir.ec = TALER_JSON_get_error_code (j);
    127     break;
    128   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    129     /* Server had an internal issue; we should retry, but this API
    130        leaves this to the application */
    131     ir.ec = TALER_JSON_get_error_code (j);
    132     break;
    133   default:
    134     /* unexpected response code */
    135     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    136                 "Unexpected response code %u\n",
    137                 (unsigned int) response_code);
    138     GNUNET_break (0);
    139     ir.ec = TALER_JSON_get_error_code (j);
    140     break;
    141   }
    142   aai->cb (aai->cb_cls,
    143            &ir);
    144   TALER_BANK_account_token_cancel (aai);
    145 }
    146 
    147 
    148 /**
    149  * Convert @a scope to string.
    150  *
    151  * @param scope a scope
    152  * @return string encoding of the scope
    153  */
    154 static const char *
    155 scope_to_string (enum TALER_BANK_TokenScope scope)
    156 {
    157   switch (scope)
    158   {
    159   case TALER_BANK_TOKEN_SCOPE_READONLY:
    160     return "readonly";
    161   case TALER_BANK_TOKEN_SCOPE_READWRITE:
    162     return "readwrite";
    163   case TALER_BANK_TOKEN_SCOPE_REVENUE:
    164     return "revenue";
    165   case TALER_BANK_TOKEN_SCOPE_WIREGATEWAY:
    166     return "wiregateway";
    167   }
    168   GNUNET_break (0);
    169   return NULL;
    170 }
    171 
    172 
    173 struct TALER_BANK_AccountTokenHandle *
    174 TALER_BANK_account_token (
    175   struct GNUNET_CURL_Context *ctx,
    176   const struct TALER_BANK_AuthenticationData *auth,
    177   const char *account_name,
    178   enum TALER_BANK_TokenScope scope,
    179   bool refreshable,
    180   const char *description,
    181   struct GNUNET_TIME_Relative duration,
    182   TALER_BANK_AccountTokenCallback res_cb,
    183   void *res_cb_cls)
    184 {
    185   struct TALER_BANK_AccountTokenHandle *ath;
    186   json_t *token_req;
    187   CURL *eh;
    188 
    189   token_req = GNUNET_JSON_PACK (
    190     GNUNET_JSON_pack_string ("scope",
    191                              scope_to_string (scope)),
    192     GNUNET_JSON_pack_allow_null (
    193       GNUNET_JSON_pack_string ("description",
    194                                description)),
    195     GNUNET_JSON_pack_allow_null (
    196       GNUNET_JSON_pack_time_rel ("duration",
    197                                  duration)),
    198     GNUNET_JSON_pack_allow_null (
    199       GNUNET_JSON_pack_bool ("refreshable",
    200                              refreshable)));
    201   if (NULL == token_req)
    202   {
    203     GNUNET_break (0);
    204     return NULL;
    205   }
    206   ath = GNUNET_new (struct TALER_BANK_AccountTokenHandle);
    207   ath->cb = res_cb;
    208   ath->cb_cls = res_cb_cls;
    209   {
    210     char *path;
    211 
    212     GNUNET_asprintf (&path,
    213                      "accounts/%s/token",
    214                      account_name);
    215     ath->request_url = TALER_url_join (auth->wire_gateway_url,
    216                                        path,
    217                                        NULL);
    218     GNUNET_free (path);
    219   }
    220   if (NULL == ath->request_url)
    221   {
    222     GNUNET_free (ath);
    223     json_decref (token_req);
    224     return NULL;
    225   }
    226   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    227               "Requesting access token at `%s'\n",
    228               ath->request_url);
    229   ath->post_ctx.headers
    230     = curl_slist_append (
    231         ath->post_ctx.headers,
    232         "Content-Type: application/json");
    233   eh = curl_easy_init ();
    234   if ( (NULL == eh) ||
    235        (GNUNET_OK !=
    236         TALER_BANK_setup_auth_ (eh,
    237                                 auth)) ||
    238        (CURLE_OK !=
    239         curl_easy_setopt (eh,
    240                           CURLOPT_URL,
    241                           ath->request_url)) ||
    242        (GNUNET_OK !=
    243         TALER_curl_easy_post (&ath->post_ctx,
    244                               eh,
    245                               token_req)) )
    246   {
    247     GNUNET_break (0);
    248     TALER_BANK_account_token_cancel (ath);
    249     if (NULL != eh)
    250       curl_easy_cleanup (eh);
    251     json_decref (token_req);
    252     return NULL;
    253   }
    254   json_decref (token_req);
    255   ath->job = GNUNET_CURL_job_add2 (ctx,
    256                                    eh,
    257                                    ath->post_ctx.headers,
    258                                    &handle_account_token_finished,
    259                                    ath);
    260   GNUNET_assert (NULL != ath->job);
    261   return ath;
    262 }
    263 
    264 
    265 void
    266 TALER_BANK_account_token_cancel (
    267   struct TALER_BANK_AccountTokenHandle *ath)
    268 {
    269   if (NULL != ath->job)
    270   {
    271     GNUNET_CURL_job_cancel (ath->job);
    272     ath->job = NULL;
    273   }
    274   TALER_curl_easy_post_finished (&ath->post_ctx);
    275   GNUNET_free (ath->request_url);
    276   GNUNET_free (ath);
    277 }
    278 
    279 
    280 /* end of bank_api_account_token.c */