bank_api_admin_add_incoming.c (7331B)
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_admin_add_incoming.c 19 * @brief Implementation of the /admin/add-incoming 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 /** 29 * @brief An /admin/add-incoming Handle 30 */ 31 struct TALER_BANK_AdminAddIncomingHandle 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_AdminAddIncomingCallback cb; 53 54 /** 55 * Closure for @a cb. 56 */ 57 void *cb_cls; 58 59 }; 60 61 62 /** 63 * Function called when we're done processing the 64 * HTTP /admin/add-incoming request. 65 * 66 * @param cls the `struct TALER_BANK_AdminAddIncomingHandle` 67 * @param response_code HTTP response code, 0 on error 68 * @param response parsed JSON result, NULL on error 69 */ 70 static void 71 handle_admin_add_incoming_finished (void *cls, 72 long response_code, 73 const void *response) 74 { 75 struct TALER_BANK_AdminAddIncomingHandle *aai = cls; 76 const json_t *j = response; 77 struct TALER_BANK_AdminAddIncomingResponse ir = { 78 .http_status = response_code, 79 .response = response 80 }; 81 82 aai->job = NULL; 83 switch (response_code) 84 { 85 case 0: 86 ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 87 break; 88 case MHD_HTTP_OK: 89 { 90 struct GNUNET_JSON_Specification spec[] = { 91 GNUNET_JSON_spec_uint64 ("row_id", 92 &ir.details.ok.serial_id), 93 GNUNET_JSON_spec_timestamp ("timestamp", 94 &ir.details.ok.timestamp), 95 GNUNET_JSON_spec_end () 96 }; 97 98 if (GNUNET_OK != 99 GNUNET_JSON_parse (j, 100 spec, 101 NULL, NULL)) 102 { 103 GNUNET_break_op (0); 104 ir.http_status = 0; 105 ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 106 break; 107 } 108 } 109 break; 110 case MHD_HTTP_BAD_REQUEST: 111 /* This should never happen, either us or the bank is buggy 112 (or API version conflict); just pass JSON reply to the application */ 113 GNUNET_break_op (0); 114 ir.ec = TALER_JSON_get_error_code (j); 115 break; 116 case MHD_HTTP_FORBIDDEN: 117 /* Access denied */ 118 ir.ec = TALER_JSON_get_error_code (j); 119 break; 120 case MHD_HTTP_UNAUTHORIZED: 121 /* Nothing really to verify, bank says the password is invalid; we should 122 pass the JSON reply to the application */ 123 ir.ec = TALER_JSON_get_error_code (j); 124 break; 125 case MHD_HTTP_NOT_FOUND: 126 /* Nothing really to verify, maybe account really does not exist. 127 We should pass the JSON reply to the application */ 128 ir.ec = TALER_JSON_get_error_code (j); 129 break; 130 case MHD_HTTP_CONFLICT: 131 /* Nothing to verify, we used the same wire subject 132 twice? */ 133 ir.ec = TALER_JSON_get_error_code (j); 134 break; 135 case MHD_HTTP_INTERNAL_SERVER_ERROR: 136 /* Server had an internal issue; we should retry, but this API 137 leaves this to the application */ 138 ir.ec = TALER_JSON_get_error_code (j); 139 break; 140 default: 141 /* unexpected response code */ 142 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 143 "Unexpected response code %u\n", 144 (unsigned int) response_code); 145 GNUNET_break (0); 146 ir.ec = TALER_JSON_get_error_code (j); 147 break; 148 } 149 aai->cb (aai->cb_cls, 150 &ir); 151 TALER_BANK_admin_add_incoming_cancel (aai); 152 } 153 154 155 struct TALER_BANK_AdminAddIncomingHandle * 156 TALER_BANK_admin_add_incoming ( 157 struct GNUNET_CURL_Context *ctx, 158 const struct TALER_BANK_AuthenticationData *auth, 159 const struct TALER_ReservePublicKeyP *reserve_pub, 160 const struct TALER_Amount *amount, 161 const struct TALER_FullPayto debit_account, 162 TALER_BANK_AdminAddIncomingCallback res_cb, 163 void *res_cb_cls) 164 { 165 struct TALER_BANK_AdminAddIncomingHandle *aai; 166 json_t *admin_obj; 167 CURL *eh; 168 169 if (NULL == debit_account.full_payto) 170 { 171 GNUNET_break (0); 172 return NULL; 173 } 174 if (NULL == reserve_pub) 175 { 176 GNUNET_break (0); 177 return NULL; 178 } 179 if (NULL == amount) 180 { 181 GNUNET_break (0); 182 return NULL; 183 } 184 admin_obj = GNUNET_JSON_PACK ( 185 GNUNET_JSON_pack_data_auto ("reserve_pub", 186 reserve_pub), 187 TALER_JSON_pack_amount ("amount", 188 amount), 189 TALER_JSON_pack_full_payto ("debit_account", 190 debit_account)); 191 if (NULL == admin_obj) 192 { 193 GNUNET_break (0); 194 return NULL; 195 } 196 aai = GNUNET_new (struct TALER_BANK_AdminAddIncomingHandle); 197 aai->cb = res_cb; 198 aai->cb_cls = res_cb_cls; 199 aai->request_url = TALER_url_join (auth->wire_gateway_url, 200 "admin/add-incoming", 201 NULL); 202 if (NULL == aai->request_url) 203 { 204 GNUNET_free (aai); 205 json_decref (admin_obj); 206 return NULL; 207 } 208 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 209 "Requesting administrative transaction at `%s' for reserve %s\n", 210 aai->request_url, 211 TALER_B2S (reserve_pub)); 212 aai->post_ctx.headers 213 = curl_slist_append ( 214 aai->post_ctx.headers, 215 "Content-Type: application/json"); 216 217 eh = curl_easy_init (); 218 if ( (NULL == eh) || 219 (GNUNET_OK != 220 TALER_BANK_setup_auth_ (eh, 221 auth)) || 222 (CURLE_OK != 223 curl_easy_setopt (eh, 224 CURLOPT_URL, 225 aai->request_url)) || 226 (GNUNET_OK != 227 TALER_curl_easy_post (&aai->post_ctx, 228 eh, 229 admin_obj)) ) 230 { 231 GNUNET_break (0); 232 TALER_BANK_admin_add_incoming_cancel (aai); 233 if (NULL != eh) 234 curl_easy_cleanup (eh); 235 json_decref (admin_obj); 236 return NULL; 237 } 238 json_decref (admin_obj); 239 240 aai->job = GNUNET_CURL_job_add2 (ctx, 241 eh, 242 aai->post_ctx.headers, 243 &handle_admin_add_incoming_finished, 244 aai); 245 return aai; 246 } 247 248 249 void 250 TALER_BANK_admin_add_incoming_cancel ( 251 struct TALER_BANK_AdminAddIncomingHandle *aai) 252 { 253 if (NULL != aai->job) 254 { 255 GNUNET_CURL_job_cancel (aai->job); 256 aai->job = NULL; 257 } 258 TALER_curl_easy_post_finished (&aai->post_ctx); 259 GNUNET_free (aai->request_url); 260 GNUNET_free (aai); 261 } 262 263 264 /* end of bank_api_admin_add_incoming.c */