merchant_api_post_account.c (7099B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2023 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify 6 it under the terms of the GNU Lesser General Public License as 7 published by the Free Software Foundation; either version 2.1, 8 or (at your option) any later version. 9 10 TALER is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General 16 Public License along with TALER; see the file COPYING.LGPL. 17 If not, see <http://www.gnu.org/licenses/> 18 */ 19 /** 20 * @file merchant_api_post_account.c 21 * @brief Implementation of the POST /account request 22 * of the merchant's HTTP API 23 * @author Christian Grothoff 24 */ 25 #include "platform.h" 26 #include <curl/curl.h> 27 #include <jansson.h> 28 #include <microhttpd.h> /* just for HTTP status codes */ 29 #include <gnunet/gnunet_util_lib.h> 30 #include "taler_merchant_service.h" 31 #include "merchant_api_curl_defaults.h" 32 #include "merchant_api_common.h" 33 #include <taler/taler_json_lib.h> 34 #include <taler/taler_curl_lib.h> 35 36 37 /** 38 * Handle for a POST /private/accounts operation. 39 */ 40 struct TALER_MERCHANT_AccountsPostHandle 41 { 42 43 /** 44 * The url for this request. 45 */ 46 char *url; 47 48 /** 49 * Handle for the request. 50 */ 51 struct GNUNET_CURL_Job *job; 52 53 /** 54 * Function to call with the result. 55 */ 56 TALER_MERCHANT_AccountsPostCallback cb; 57 58 /** 59 * Closure for @a cb. 60 */ 61 void *cb_cls; 62 63 /** 64 * Reference to the execution context. 65 */ 66 struct GNUNET_CURL_Context *ctx; 67 68 /** 69 * Minor context that holds body and headers. 70 */ 71 struct TALER_CURL_PostContext post_ctx; 72 73 }; 74 75 76 /** 77 * Function called when we're done processing the 78 * HTTP POST /account request. 79 * 80 * @param cls the `struct TALER_MERCHANT_AccountPostHandle` 81 * @param response_code HTTP response code, 0 on error 82 * @param response response body, NULL if not in JSON 83 */ 84 static void 85 handle_post_account_finished (void *cls, 86 long response_code, 87 const void *response) 88 { 89 struct TALER_MERCHANT_AccountsPostHandle *aph = cls; 90 const json_t *json = response; 91 struct TALER_MERCHANT_AccountsPostResponse apr = { 92 .hr.http_status = (unsigned int) response_code, 93 .hr.reply = json 94 }; 95 96 aph->job = NULL; 97 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 98 "POST /accounts completed with response code %u\n", 99 (unsigned int) response_code); 100 switch (response_code) 101 { 102 case 0: 103 apr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 104 break; 105 case MHD_HTTP_OK: 106 { 107 struct GNUNET_JSON_Specification spec[] = { 108 GNUNET_JSON_spec_fixed_auto ("h_wire", 109 &apr.details.ok.h_wire), 110 GNUNET_JSON_spec_fixed_auto ("salt", 111 &apr.details.ok.salt), 112 GNUNET_JSON_spec_end () 113 }; 114 115 if (GNUNET_OK != 116 GNUNET_JSON_parse (json, 117 spec, 118 NULL, NULL)) 119 { 120 GNUNET_break_op (0); 121 apr.hr.http_status = 0; 122 apr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 123 break; 124 } 125 } 126 break; 127 case MHD_HTTP_BAD_REQUEST: 128 GNUNET_break_op (0); 129 apr.hr.ec = TALER_JSON_get_error_code (json); 130 apr.hr.hint = TALER_JSON_get_error_hint (json); 131 /* This should never happen, either us 132 * or the merchant is buggy (or API version conflict); 133 * just pass JSON reply to the application */ 134 break; 135 case MHD_HTTP_FORBIDDEN: 136 apr.hr.ec = TALER_JSON_get_error_code (json); 137 apr.hr.hint = TALER_JSON_get_error_hint (json); 138 break; 139 case MHD_HTTP_NOT_FOUND: 140 apr.hr.ec = TALER_JSON_get_error_code (json); 141 apr.hr.hint = TALER_JSON_get_error_hint (json); 142 /* Nothing really to verify, this should never 143 happen, we should pass the JSON reply to the 144 application */ 145 break; 146 case MHD_HTTP_CONFLICT: 147 apr.hr.ec = TALER_JSON_get_error_code (json); 148 apr.hr.hint = TALER_JSON_get_error_hint (json); 149 break; 150 case MHD_HTTP_INTERNAL_SERVER_ERROR: 151 apr.hr.ec = TALER_JSON_get_error_code (json); 152 apr.hr.hint = TALER_JSON_get_error_hint (json); 153 /* Server had an internal issue; we should retry, 154 but this API leaves this to the application */ 155 break; 156 default: 157 TALER_MERCHANT_parse_error_details_ (json, 158 response_code, 159 &apr.hr); 160 /* unexpected response code */ 161 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 162 "Unexpected response code %u/%d\n", 163 (unsigned int) response_code, 164 (int) apr.hr.ec); 165 GNUNET_break_op (0); 166 break; 167 } 168 aph->cb (aph->cb_cls, 169 &apr); 170 TALER_MERCHANT_accounts_post_cancel (aph); 171 } 172 173 174 struct TALER_MERCHANT_AccountsPostHandle * 175 TALER_MERCHANT_accounts_post ( 176 struct GNUNET_CURL_Context *ctx, 177 const char *backend_url, 178 struct TALER_FullPayto payto_uri, 179 const char *credit_facade_url, 180 const json_t *credit_facade_credentials, 181 TALER_MERCHANT_AccountsPostCallback cb, 182 void *cb_cls) 183 { 184 struct TALER_MERCHANT_AccountsPostHandle *aph; 185 json_t *req_obj; 186 187 req_obj = GNUNET_JSON_PACK ( 188 TALER_JSON_pack_full_payto ( 189 "payto_uri", 190 payto_uri), 191 GNUNET_JSON_pack_allow_null ( 192 GNUNET_JSON_pack_string ( 193 "credit_facade_url", 194 credit_facade_url)), 195 GNUNET_JSON_pack_allow_null ( 196 GNUNET_JSON_pack_object_incref ( 197 "credit_facade_credentials", 198 (json_t *) credit_facade_credentials)) 199 ); 200 aph = GNUNET_new (struct TALER_MERCHANT_AccountsPostHandle); 201 aph->ctx = ctx; 202 aph->cb = cb; 203 aph->cb_cls = cb_cls; 204 aph->url = TALER_url_join (backend_url, 205 "private/accounts", 206 NULL); 207 if (NULL == aph->url) 208 { 209 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 210 "Could not construct request URL.\n"); 211 json_decref (req_obj); 212 GNUNET_free (aph); 213 return NULL; 214 } 215 { 216 CURL *eh; 217 218 eh = TALER_MERCHANT_curl_easy_get_ (aph->url); 219 GNUNET_assert (GNUNET_OK == 220 TALER_curl_easy_post (&aph->post_ctx, 221 eh, 222 req_obj)); 223 json_decref (req_obj); 224 aph->job = GNUNET_CURL_job_add2 (ctx, 225 eh, 226 aph->post_ctx.headers, 227 &handle_post_account_finished, 228 aph); 229 GNUNET_assert (NULL != aph->job); 230 } 231 return aph; 232 } 233 234 235 void 236 TALER_MERCHANT_accounts_post_cancel ( 237 struct TALER_MERCHANT_AccountsPostHandle *aph) 238 { 239 if (NULL != aph->job) 240 { 241 GNUNET_CURL_job_cancel (aph->job); 242 aph->job = NULL; 243 } 244 TALER_curl_easy_post_finished (&aph->post_ctx); 245 GNUNET_free (aph->url); 246 GNUNET_free (aph); 247 } 248 249 250 /* end of merchant_api_post_account.c */