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 (7363B)


      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 "bank_api_common.h"
     23 #include <microhttpd.h> /* just for HTTP status codes */
     24 #include "taler/taler_signatures.h"
     25 #include "taler/taler_curl_lib.h"
     26 
     27 
     28 struct TALER_BANK_AccountTokenHandle
     29 {
     30 
     31   /**
     32    * The url for this request.
     33    */
     34   char *request_url;
     35 
     36   /**
     37    * POST context.
     38    */
     39   struct TALER_CURL_PostContext post_ctx;
     40 
     41   /**
     42    * Handle for the request.
     43    */
     44   struct GNUNET_CURL_Job *job;
     45 
     46   /**
     47    * Function to call with the result.
     48    */
     49   TALER_BANK_AccountTokenCallback cb;
     50 
     51   /**
     52    * Closure for @a cb.
     53    */
     54   void *cb_cls;
     55 
     56 };
     57 
     58 
     59 /**
     60  * Function called when we're done processing the
     61  * HTTP /account/$ACC/token request.
     62  *
     63  * @param cls the `struct TALER_BANK_AccountTokenHandle`
     64  * @param response_code HTTP response code, 0 on error
     65  * @param response parsed JSON result, NULL on error
     66  */
     67 static void
     68 handle_account_token_finished (void *cls,
     69                                long response_code,
     70                                const void *response)
     71 {
     72   struct TALER_BANK_AccountTokenHandle *aai = cls;
     73   const json_t *j = response;
     74   struct TALER_BANK_AccountTokenResponse ir = {
     75     .http_status = response_code,
     76     .response = response
     77   };
     78 
     79   aai->job = NULL;
     80   switch (response_code)
     81   {
     82   case 0:
     83     ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     84     break;
     85   case MHD_HTTP_OK:
     86     {
     87       struct GNUNET_JSON_Specification spec[] = {
     88         GNUNET_JSON_spec_string ("access_token",
     89                                  &ir.details.ok.access_token),
     90         GNUNET_JSON_spec_timestamp ("expiration",
     91                                     &ir.details.ok.expiration),
     92         GNUNET_JSON_spec_end ()
     93       };
     94 
     95       if (GNUNET_OK !=
     96           GNUNET_JSON_parse (j,
     97                              spec,
     98                              NULL, NULL))
     99       {
    100         GNUNET_break_op (0);
    101         ir.http_status = 0;
    102         ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    103         break;
    104       }
    105     }
    106     break;
    107   case MHD_HTTP_BAD_REQUEST:
    108     /* This should never happen, either us or the bank is buggy
    109        (or API version conflict); just pass JSON reply to the application */
    110     GNUNET_break_op (0);
    111     ir.ec = TALER_JSON_get_error_code (j);
    112     break;
    113   case MHD_HTTP_FORBIDDEN:
    114     /* Access denied */
    115     ir.ec = TALER_JSON_get_error_code (j);
    116     break;
    117   case MHD_HTTP_UNAUTHORIZED:
    118     /* Nothing really to verify, bank says the password is invalid; we should
    119        pass the JSON reply to the application */
    120     ir.ec = TALER_JSON_get_error_code (j);
    121     break;
    122   case MHD_HTTP_NOT_FOUND:
    123     /* Nothing really to verify, maybe account really does not exist.
    124        We should pass the JSON reply to the application */
    125     ir.ec = TALER_JSON_get_error_code (j);
    126     break;
    127   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    128     /* Server had an internal issue; we should retry, but this API
    129        leaves this to the application */
    130     ir.ec = TALER_JSON_get_error_code (j);
    131     break;
    132   default:
    133     /* unexpected response code */
    134     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    135                 "Unexpected response code %u\n",
    136                 (unsigned int) response_code);
    137     GNUNET_break (0);
    138     ir.ec = TALER_JSON_get_error_code (j);
    139     break;
    140   }
    141   aai->cb (aai->cb_cls,
    142            &ir);
    143   TALER_BANK_account_token_cancel (aai);
    144 }
    145 
    146 
    147 /**
    148  * Convert @a scope to string.
    149  *
    150  * @param scope a scope
    151  * @return string encoding of the scope
    152  */
    153 static const char *
    154 scope_to_string (enum TALER_BANK_TokenScope scope)
    155 {
    156   switch (scope)
    157   {
    158   case TALER_BANK_TOKEN_SCOPE_READONLY:
    159     return "readonly";
    160   case TALER_BANK_TOKEN_SCOPE_READWRITE:
    161     return "readwrite";
    162   case TALER_BANK_TOKEN_SCOPE_REVENUE:
    163     return "revenue";
    164   case TALER_BANK_TOKEN_SCOPE_WIREGATEWAY:
    165     return "wiregateway";
    166   }
    167   GNUNET_break (0);
    168   return NULL;
    169 }
    170 
    171 
    172 struct TALER_BANK_AccountTokenHandle *
    173 TALER_BANK_account_token (
    174   struct GNUNET_CURL_Context *ctx,
    175   const struct TALER_BANK_AuthenticationData *auth,
    176   const char *account_name,
    177   enum TALER_BANK_TokenScope scope,
    178   bool refreshable,
    179   const char *description,
    180   struct GNUNET_TIME_Relative duration,
    181   TALER_BANK_AccountTokenCallback res_cb,
    182   void *res_cb_cls)
    183 {
    184   struct TALER_BANK_AccountTokenHandle *ath;
    185   json_t *token_req;
    186   CURL *eh;
    187 
    188   token_req = GNUNET_JSON_PACK (
    189     GNUNET_JSON_pack_string ("scope",
    190                              scope_to_string (scope)),
    191     GNUNET_JSON_pack_allow_null (
    192       GNUNET_JSON_pack_string ("description",
    193                                description)),
    194     GNUNET_JSON_pack_allow_null (
    195       GNUNET_JSON_pack_time_rel ("duration",
    196                                  duration)),
    197     GNUNET_JSON_pack_allow_null (
    198       GNUNET_JSON_pack_bool ("refreshable",
    199                              refreshable)));
    200   if (NULL == token_req)
    201   {
    202     GNUNET_break (0);
    203     return NULL;
    204   }
    205   ath = GNUNET_new (struct TALER_BANK_AccountTokenHandle);
    206   ath->cb = res_cb;
    207   ath->cb_cls = res_cb_cls;
    208   ath->request_url = TALER_url_join (auth->core_bank_url,
    209                                      "token",
    210                                      NULL);
    211   if (NULL == ath->request_url)
    212   {
    213     GNUNET_free (ath);
    214     json_decref (token_req);
    215     return NULL;
    216   }
    217   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    218               "Requesting access token at `%s'\n",
    219               ath->request_url);
    220   eh = curl_easy_init ();
    221   if ( (NULL == eh) ||
    222        (GNUNET_OK !=
    223         TALER_BANK_setup_auth_ (eh,
    224                                 auth)) ||
    225        (CURLE_OK !=
    226         curl_easy_setopt (eh,
    227                           CURLOPT_URL,
    228                           ath->request_url)) ||
    229        (GNUNET_OK !=
    230         TALER_curl_easy_post (&ath->post_ctx,
    231                               eh,
    232                               token_req)) )
    233   {
    234     GNUNET_break (0);
    235     TALER_BANK_account_token_cancel (ath);
    236     if (NULL != eh)
    237       curl_easy_cleanup (eh);
    238     json_decref (token_req);
    239     return NULL;
    240   }
    241   json_decref (token_req);
    242   ath->job = GNUNET_CURL_job_add2 (ctx,
    243                                    eh,
    244                                    ath->post_ctx.headers,
    245                                    &handle_account_token_finished,
    246                                    ath);
    247   GNUNET_assert (NULL != ath->job);
    248   return ath;
    249 }
    250 
    251 
    252 void
    253 TALER_BANK_account_token_cancel (
    254   struct TALER_BANK_AccountTokenHandle *ath)
    255 {
    256   if (NULL != ath->job)
    257   {
    258     GNUNET_CURL_job_cancel (ath->job);
    259     ath->job = NULL;
    260   }
    261   TALER_curl_easy_post_finished (&ath->post_ctx);
    262   GNUNET_free (ath->request_url);
    263   GNUNET_free (ath);
    264 }
    265 
    266 
    267 /* end of bank_api_account_token.c */