exchange

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

exchange_api_kyc_wallet.c (7168B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2021 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 lib/exchange_api_kyc_wallet.c
     19  * @brief Implementation of the /kyc-wallet request
     20  * @author Christian Grothoff
     21  */
     22 #include "taler/platform.h"
     23 #include <microhttpd.h> /* just for HTTP wallet codes */
     24 #include <gnunet/gnunet_util_lib.h>
     25 #include <gnunet/gnunet_curl_lib.h>
     26 #include "taler/taler_exchange_service.h"
     27 #include "taler/taler_json_lib.h"
     28 #include "exchange_api_handle.h"
     29 #include "taler/taler_signatures.h"
     30 #include "exchange_api_curl_defaults.h"
     31 
     32 
     33 /**
     34  * @brief A ``/kyc-wallet`` handle
     35  */
     36 struct TALER_EXCHANGE_KycWalletHandle
     37 {
     38 
     39   /**
     40    * Context for #TEH_curl_easy_post(). Keeps the data that must
     41    * persist for Curl to make the upload.
     42    */
     43   struct TALER_CURL_PostContext ctx;
     44 
     45   /**
     46    * The url for this request.
     47    */
     48   char *url;
     49 
     50   /**
     51    * Handle for the request.
     52    */
     53   struct GNUNET_CURL_Job *job;
     54 
     55   /**
     56    * Function to call with the result.
     57    */
     58   TALER_EXCHANGE_KycWalletCallback cb;
     59 
     60   /**
     61    * Closure for @e cb.
     62    */
     63   void *cb_cls;
     64 
     65 };
     66 
     67 
     68 /**
     69  * Function called when we're done processing the
     70  * HTTP /kyc-wallet request.
     71  *
     72  * @param cls the `struct TALER_EXCHANGE_KycWalletHandle`
     73  * @param response_code HTTP response code, 0 on error
     74  * @param response parsed JSON result, NULL on error
     75  */
     76 static void
     77 handle_kyc_wallet_finished (void *cls,
     78                             long response_code,
     79                             const void *response)
     80 {
     81   struct TALER_EXCHANGE_KycWalletHandle *kwh = cls;
     82   const json_t *j = response;
     83   struct TALER_EXCHANGE_WalletKycResponse ks = {
     84     .hr.reply = j,
     85     .hr.http_status = (unsigned int) response_code
     86   };
     87 
     88   kwh->job = NULL;
     89   switch (response_code)
     90   {
     91   case 0:
     92     ks.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     93     break;
     94   case MHD_HTTP_OK:
     95     {
     96       struct GNUNET_JSON_Specification spec[] = {
     97         GNUNET_JSON_spec_mark_optional (
     98           TALER_JSON_spec_amount_any (
     99             "next_threshold",
    100             &ks.details.ok.next_threshold),
    101           NULL),
    102         GNUNET_JSON_spec_timestamp (
    103           "expiration_time",
    104           &ks.details.ok.expiration_time),
    105         GNUNET_JSON_spec_end ()
    106       };
    107 
    108       if (GNUNET_OK !=
    109           GNUNET_JSON_parse (j,
    110                              spec,
    111                              NULL, NULL))
    112       {
    113         GNUNET_break_op (0);
    114         ks.hr.http_status = 0;
    115         ks.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    116         break;
    117       }
    118       break;
    119     }
    120   case MHD_HTTP_NO_CONTENT:
    121     break;
    122   case MHD_HTTP_BAD_REQUEST:
    123     ks.hr.ec = TALER_JSON_get_error_code (j);
    124     /* This should never happen, either us or the exchange is buggy
    125        (or API version conflict); just pass JSON reply to the application */
    126     break;
    127   case MHD_HTTP_FORBIDDEN:
    128     ks.hr.ec = TALER_JSON_get_error_code (j);
    129     break;
    130   case MHD_HTTP_NOT_FOUND:
    131     ks.hr.ec = TALER_JSON_get_error_code (j);
    132     break;
    133   case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
    134     {
    135       struct GNUNET_JSON_Specification spec[] = {
    136         GNUNET_JSON_spec_fixed_auto (
    137           "h_payto",
    138           &ks.details.unavailable_for_legal_reasons.h_payto),
    139         GNUNET_JSON_spec_uint64 (
    140           "requirement_row",
    141           &ks.details.unavailable_for_legal_reasons.requirement_row),
    142         GNUNET_JSON_spec_end ()
    143       };
    144 
    145       if (GNUNET_OK !=
    146           GNUNET_JSON_parse (j,
    147                              spec,
    148                              NULL, NULL))
    149       {
    150         GNUNET_break_op (0);
    151         ks.hr.http_status = 0;
    152         ks.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    153         break;
    154       }
    155       break;
    156     }
    157   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    158     ks.hr.ec = TALER_JSON_get_error_code (j);
    159     /* Server had an internal issue; we should retry, but this API
    160        leaves this to the application */
    161     break;
    162   default:
    163     /* unexpected response code */
    164     GNUNET_break_op (0);
    165     ks.hr.ec = TALER_JSON_get_error_code (j);
    166     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    167                 "Unexpected response code %u/%d for exchange /kyc-wallet\n",
    168                 (unsigned int) response_code,
    169                 (int) ks.hr.ec);
    170     break;
    171   }
    172   kwh->cb (kwh->cb_cls,
    173            &ks);
    174   TALER_EXCHANGE_kyc_wallet_cancel (kwh);
    175 }
    176 
    177 
    178 struct TALER_EXCHANGE_KycWalletHandle *
    179 TALER_EXCHANGE_kyc_wallet (
    180   struct GNUNET_CURL_Context *ctx,
    181   const char *url,
    182   const struct TALER_ReservePrivateKeyP *reserve_priv,
    183   const struct TALER_Amount *balance,
    184   TALER_EXCHANGE_KycWalletCallback cb,
    185   void *cb_cls)
    186 {
    187   struct TALER_EXCHANGE_KycWalletHandle *kwh;
    188   CURL *eh;
    189   json_t *req;
    190   struct TALER_ReservePublicKeyP reserve_pub;
    191   struct TALER_ReserveSignatureP reserve_sig;
    192 
    193   GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
    194                                       &reserve_pub.eddsa_pub);
    195   TALER_wallet_account_setup_sign (reserve_priv,
    196                                    balance,
    197                                    &reserve_sig);
    198   req = GNUNET_JSON_PACK (
    199     TALER_JSON_pack_amount ("balance",
    200                             balance),
    201     GNUNET_JSON_pack_data_auto ("reserve_pub",
    202                                 &reserve_pub),
    203     GNUNET_JSON_pack_data_auto ("reserve_sig",
    204                                 &reserve_sig));
    205   GNUNET_assert (NULL != req);
    206   kwh = GNUNET_new (struct TALER_EXCHANGE_KycWalletHandle);
    207   kwh->cb = cb;
    208   kwh->cb_cls = cb_cls;
    209   kwh->url = TALER_url_join (url,
    210                              "kyc-wallet",
    211                              NULL);
    212   if (NULL == kwh->url)
    213   {
    214     json_decref (req);
    215     GNUNET_free (kwh);
    216     return NULL;
    217   }
    218   eh = TALER_EXCHANGE_curl_easy_get_ (kwh->url);
    219   if ( (NULL == eh) ||
    220        (GNUNET_OK !=
    221         TALER_curl_easy_post (&kwh->ctx,
    222                               eh,
    223                               req)) )
    224   {
    225     GNUNET_break (0);
    226     if (NULL != eh)
    227       curl_easy_cleanup (eh);
    228     json_decref (req);
    229     GNUNET_free (kwh->url);
    230     GNUNET_free (kwh);
    231     return NULL;
    232   }
    233   json_decref (req);
    234   kwh->job = GNUNET_CURL_job_add2 (ctx,
    235                                    eh,
    236                                    kwh->ctx.headers,
    237                                    &handle_kyc_wallet_finished,
    238                                    kwh);
    239   return kwh;
    240 }
    241 
    242 
    243 void
    244 TALER_EXCHANGE_kyc_wallet_cancel (struct TALER_EXCHANGE_KycWalletHandle *kwh)
    245 {
    246   if (NULL != kwh->job)
    247   {
    248     GNUNET_CURL_job_cancel (kwh->job);
    249     kwh->job = NULL;
    250   }
    251   GNUNET_free (kwh->url);
    252   TALER_curl_easy_post_finished (&kwh->ctx);
    253   GNUNET_free (kwh);
    254 }
    255 
    256 
    257 /* end of exchange_api_kyc_wallet.c */