LCOV - code coverage report
Current view: top level - bank-lib - bank_api_registration.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 138 0
Test Date: 2026-03-10 12:10:57 Functions: 0.0 % 4 0

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2026 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_registration.c
      19              :  * @brief Implementation of the POST /registration request 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              : /**
      30              :  * @brief A /registration Handle
      31              :  */
      32              : struct TALER_BANK_RegistrationHandle
      33              : {
      34              : 
      35              :   /**
      36              :    * The URL for this request.
      37              :    */
      38              :   char *request_url;
      39              : 
      40              :   /**
      41              :    * POST context.
      42              :    */
      43              :   struct TALER_CURL_PostContext post_ctx;
      44              : 
      45              :   /**
      46              :    * Handle for the request.
      47              :    */
      48              :   struct GNUNET_CURL_Job *job;
      49              : 
      50              :   /**
      51              :    * Function to call with the result.
      52              :    */
      53              :   TALER_BANK_RegistrationCallback cb;
      54              : 
      55              :   /**
      56              :    * Closure for @a cb.
      57              :    */
      58              :   void *cb_cls;
      59              : 
      60              : };
      61              : 
      62              : 
      63              : /**
      64              :  * Parse the "subject" field of a successful /registration response.
      65              :  * The field is a JSON object discriminated by "type".
      66              :  *
      67              :  * @param subject_json the JSON object to parse (the inner "subject" value)
      68              :  * @param[out] ts set to the parsed transfer subject on success
      69              :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
      70              :  */
      71              : static enum GNUNET_GenericReturnValue
      72            0 : parse_transfer_subject (const json_t *subject_json,
      73              :                         struct TALER_BANK_TransferSubject *ts)
      74              : {
      75              :   const char *type_str;
      76              :   struct GNUNET_JSON_Specification type_spec[] = {
      77            0 :     GNUNET_JSON_spec_string ("type",
      78              :                              &type_str),
      79            0 :     GNUNET_JSON_spec_end ()
      80              :   };
      81              : 
      82            0 :   if (GNUNET_OK !=
      83            0 :       GNUNET_JSON_parse (subject_json,
      84              :                          type_spec,
      85              :                          NULL,
      86              :                          NULL))
      87              :   {
      88            0 :     GNUNET_break_op (0);
      89            0 :     return GNUNET_SYSERR;
      90              :   }
      91              : 
      92            0 :   if (0 == strcasecmp (type_str,
      93              :                        "SIMPLE"))
      94              :   {
      95              :     struct GNUNET_JSON_Specification spec[] = {
      96            0 :       TALER_JSON_spec_amount_any ("credit_amount",
      97              :                                   &ts->details.simple.credit_amount),
      98            0 :       GNUNET_JSON_spec_string ("subject",
      99              :                                &ts->details.simple.subject),
     100            0 :       GNUNET_JSON_spec_end ()
     101              :     };
     102              : 
     103            0 :     if (GNUNET_OK !=
     104            0 :         GNUNET_JSON_parse (subject_json,
     105              :                            spec,
     106              :                            NULL, NULL))
     107              :     {
     108            0 :       GNUNET_break_op (0);
     109            0 :       return GNUNET_SYSERR;
     110              :     }
     111            0 :     ts->format = TALER_BANK_SUBJECT_FORMAT_SIMPLE;
     112            0 :     return GNUNET_OK;
     113              :   }
     114            0 :   if (0 == strcasecmp (type_str,
     115              :                        "URI"))
     116              :   {
     117              :     struct GNUNET_JSON_Specification spec[] = {
     118            0 :       GNUNET_JSON_spec_string ("uri",
     119              :                                &ts->details.uri.uri),
     120            0 :       GNUNET_JSON_spec_end ()
     121              :     };
     122              : 
     123            0 :     if (GNUNET_OK !=
     124            0 :         GNUNET_JSON_parse (subject_json,
     125              :                            spec,
     126              :                            NULL, NULL))
     127              :     {
     128            0 :       GNUNET_break_op (0);
     129            0 :       return GNUNET_SYSERR;
     130              :     }
     131            0 :     ts->format = TALER_BANK_SUBJECT_FORMAT_URI;
     132            0 :     return GNUNET_OK;
     133              :   }
     134            0 :   if (0 == strcasecmp (type_str,
     135              :                        "CH_QR_BILL"))
     136              :   {
     137              :     struct GNUNET_JSON_Specification spec[] = {
     138            0 :       TALER_JSON_spec_amount_any ("credit_amount",
     139              :                                   &ts->details.ch_qr_bill.credit_amount),
     140            0 :       GNUNET_JSON_spec_string ("qr_reference_number",
     141              :                                &ts->details.ch_qr_bill.qr_reference_number),
     142            0 :       GNUNET_JSON_spec_end ()
     143              :     };
     144              : 
     145            0 :     if (GNUNET_OK !=
     146            0 :         GNUNET_JSON_parse (subject_json,
     147              :                            spec,
     148              :                            NULL, NULL))
     149              :     {
     150            0 :       GNUNET_break_op (0);
     151            0 :       return GNUNET_SYSERR;
     152              :     }
     153            0 :     ts->format = TALER_BANK_SUBJECT_FORMAT_CH_QR_BILL;
     154            0 :     return GNUNET_OK;
     155              :   }
     156            0 :   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     157              :               "Unknown transfer subject type `%s'\n",
     158              :               type_str);
     159            0 :   GNUNET_break_op (0);
     160            0 :   return GNUNET_SYSERR;
     161              : }
     162              : 
     163              : 
     164              : /**
     165              :  * Function called when we're done processing the HTTP POST /registration
     166              :  * request.
     167              :  *
     168              :  * @param cls the `struct TALER_BANK_RegistrationHandle`
     169              :  * @param response_code HTTP response code, 0 on error
     170              :  * @param response parsed JSON result, NULL on error
     171              :  */
     172              : static void
     173            0 : handle_registration_finished (void *cls,
     174              :                               long response_code,
     175              :                               const void *response)
     176              : {
     177            0 :   struct TALER_BANK_RegistrationHandle *rh = cls;
     178            0 :   const json_t *j = response;
     179            0 :   struct TALER_BANK_RegistrationResponse rr = {
     180              :     .http_status = response_code,
     181              :     .response = response
     182              :   };
     183              : 
     184            0 :   rh->job = NULL;
     185            0 :   switch (response_code)
     186              :   {
     187            0 :   case 0:
     188            0 :     rr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     189            0 :     break;
     190            0 :   case MHD_HTTP_OK:
     191              :     {
     192              :       const json_t *subjects;
     193              :       struct GNUNET_JSON_Specification spec[] = {
     194            0 :         GNUNET_JSON_spec_array_const ("subjects",
     195              :                                       &subjects),
     196            0 :         GNUNET_JSON_spec_timestamp ("expiration",
     197              :                                     &rr.details.ok.expiration),
     198            0 :         GNUNET_JSON_spec_end ()
     199              :       };
     200              : 
     201            0 :       if (GNUNET_OK !=
     202            0 :           GNUNET_JSON_parse (j,
     203              :                              spec,
     204              :                              NULL, NULL))
     205              :       {
     206            0 :         GNUNET_break_op (0);
     207            0 :         rr.http_status = 0;
     208            0 :         rr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     209            0 :         break;
     210              :       }
     211              : 
     212            0 :       {
     213            0 :         size_t n = json_array_size (subjects);
     214            0 :         struct TALER_BANK_TransferSubject ts[GNUNET_NZL (n)];
     215              :         size_t i;
     216              :         const json_t *subject;
     217              : 
     218            0 :         json_array_foreach ((json_t *) subjects, i, subject)
     219              :         {
     220            0 :           if (GNUNET_OK !=
     221            0 :               parse_transfer_subject (subject,
     222              :                                       &ts[i]))
     223              :           {
     224            0 :             GNUNET_break_op (0);
     225            0 :             rr.http_status = 0;
     226            0 :             rr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     227            0 :             break;
     228              :           }
     229              :         }
     230            0 :         if (MHD_HTTP_OK == rr.http_status)
     231              :         {
     232            0 :           rr.details.ok.num_subjects = n;
     233            0 :           rr.details.ok.subjects = ts;
     234            0 :           rh->cb (rh->cb_cls,
     235              :                   &rr);
     236            0 :           TALER_BANK_registration_cancel (rh);
     237            0 :           return;
     238              :         }
     239              :       }
     240              :     }
     241            0 :     break;
     242            0 :   case MHD_HTTP_BAD_REQUEST:
     243              :     /* Either we or the service is buggy, or there is an API version conflict. */
     244            0 :     GNUNET_break_op (0);
     245            0 :     rr.ec = TALER_JSON_get_error_code (j);
     246            0 :     break;
     247            0 :   case MHD_HTTP_CONFLICT:
     248              :     /* Covers TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT,
     249              :        TALER_EC_BANK_UNSUPPORTED_SUBJECT_FORMAT,
     250              :        TALER_EC_BANK_DERIVATION_REUSE, and
     251              :        TALER_EC_BANK_BAD_SIGNATURE. */
     252            0 :     rr.ec = TALER_JSON_get_error_code (j);
     253            0 :     break;
     254            0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     255              :     /* Server had an internal issue; we should retry, but this API
     256              :        leaves that to the application. */
     257            0 :     rr.ec = TALER_JSON_get_error_code (j);
     258            0 :     break;
     259            0 :   default:
     260              :     /* unexpected response code */
     261            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     262              :                 "Unexpected response code %u\n",
     263              :                 (unsigned int) response_code);
     264            0 :     GNUNET_break (0);
     265            0 :     rr.ec = TALER_JSON_get_error_code (j);
     266            0 :     break;
     267              :   }
     268            0 :   rh->cb (rh->cb_cls,
     269              :           &rr);
     270            0 :   TALER_BANK_registration_cancel (rh);
     271              : }
     272              : 
     273              : 
     274              : struct TALER_BANK_RegistrationHandle *
     275            0 : TALER_BANK_registration (
     276              :   struct GNUNET_CURL_Context *ctx,
     277              :   const char *base_url,
     278              :   const struct TALER_Amount *credit_amount,
     279              :   enum TALER_BANK_RegistrationType type,
     280              :   const union TALER_AccountPublicKeyP *account_pub,
     281              :   const struct TALER_ReserveMapAuthorizationPrivateKeyP *authorization_priv,
     282              :   bool recurrent,
     283              :   TALER_BANK_RegistrationCallback res_cb,
     284              :   void *res_cb_cls)
     285              : {
     286              :   struct TALER_ReserveMapAuthorizationPublicKeyP authorization_pub;
     287              :   struct TALER_ReserveMapAuthorizationSignatureP authorization_sig;
     288              :   struct TALER_BANK_RegistrationHandle *rh;
     289              :   const char *type_str;
     290              :   json_t *reg_obj;
     291              :   CURL *eh;
     292              : 
     293            0 :   TALER_wallet_reserve_map_authorization_sign (account_pub,
     294              :                                                authorization_priv,
     295              :                                                &authorization_sig);
     296            0 :   GNUNET_CRYPTO_eddsa_key_get_public (&authorization_priv->eddsa_priv,
     297              :                                       &authorization_pub.eddsa_pub);
     298              : 
     299            0 :   switch (type)
     300              :   {
     301            0 :   case TALER_BANK_REGISTRATION_TYPE_RESERVE:
     302            0 :     type_str = "reserve";
     303            0 :     break;
     304            0 :   case TALER_BANK_REGISTRATION_TYPE_KYC:
     305            0 :     type_str = "kyc";
     306            0 :     break;
     307            0 :   default:
     308            0 :     GNUNET_break (0);
     309            0 :     return NULL;
     310              :   }
     311              : 
     312            0 :   reg_obj = GNUNET_JSON_PACK (
     313              :     TALER_JSON_pack_amount ("credit_amount",
     314              :                             credit_amount),
     315              :     GNUNET_JSON_pack_string ("type",
     316              :                              type_str),
     317              :     GNUNET_JSON_pack_string ("alg",
     318              :                              "EdDSA"),
     319              :     GNUNET_JSON_pack_data_auto ("account_pub",
     320              :                                 account_pub),
     321              :     GNUNET_JSON_pack_data_auto ("authorization_pub",
     322              :                                 &authorization_pub),
     323              :     GNUNET_JSON_pack_data_auto ("authorization_sig",
     324              :                                 &authorization_sig),
     325              :     GNUNET_JSON_pack_bool ("recurrent",
     326              :                            recurrent));
     327            0 :   rh = GNUNET_new (struct TALER_BANK_RegistrationHandle);
     328            0 :   rh->cb = res_cb;
     329            0 :   rh->cb_cls = res_cb_cls;
     330            0 :   rh->request_url = TALER_url_join (base_url,
     331              :                                     "registration",
     332              :                                     NULL);
     333            0 :   if (NULL == rh->request_url)
     334              :   {
     335            0 :     GNUNET_free (rh);
     336            0 :     json_decref (reg_obj);
     337            0 :     return NULL;
     338              :   }
     339            0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     340              :               "Requesting wire transfer subject registration at `%s'\n",
     341              :               rh->request_url);
     342            0 :   eh = curl_easy_init ();
     343            0 :   if ( (NULL == eh) ||
     344              :        (CURLE_OK !=
     345            0 :         curl_easy_setopt (eh,
     346              :                           CURLOPT_URL,
     347            0 :                           rh->request_url)) ||
     348              :        (GNUNET_OK !=
     349            0 :         TALER_curl_easy_post (&rh->post_ctx,
     350              :                               eh,
     351              :                               reg_obj)) )
     352              :   {
     353            0 :     GNUNET_break (0);
     354            0 :     TALER_BANK_registration_cancel (rh);
     355            0 :     if (NULL != eh)
     356            0 :       curl_easy_cleanup (eh);
     357            0 :     json_decref (reg_obj);
     358            0 :     return NULL;
     359              :   }
     360            0 :   json_decref (reg_obj);
     361            0 :   rh->job = GNUNET_CURL_job_add2 (ctx,
     362              :                                   eh,
     363            0 :                                   rh->post_ctx.headers,
     364              :                                   &handle_registration_finished,
     365              :                                   rh);
     366            0 :   return rh;
     367              : }
     368              : 
     369              : 
     370              : void
     371            0 : TALER_BANK_registration_cancel (
     372              :   struct TALER_BANK_RegistrationHandle *rh)
     373              : {
     374            0 :   if (NULL != rh->job)
     375              :   {
     376            0 :     GNUNET_CURL_job_cancel (rh->job);
     377            0 :     rh->job = NULL;
     378              :   }
     379            0 :   TALER_curl_easy_post_finished (&rh->post_ctx);
     380            0 :   GNUNET_free (rh->request_url);
     381            0 :   GNUNET_free (rh);
     382            0 : }
     383              : 
     384              : 
     385              : /* end of bank_api_registration.c */
        

Generated by: LCOV version 2.0-1