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

Generated by: LCOV version 2.0-1