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 */