bank_api_account_token.c (7391B)
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_account_token.c 19 * @brief Implementation of the /account/$ACC/token requests 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 struct TALER_BANK_AccountTokenHandle 30 { 31 32 /** 33 * The url for this request. 34 */ 35 char *request_url; 36 37 /** 38 * POST context. 39 */ 40 struct TALER_CURL_PostContext post_ctx; 41 42 /** 43 * Handle for the request. 44 */ 45 struct GNUNET_CURL_Job *job; 46 47 /** 48 * Function to call with the result. 49 */ 50 TALER_BANK_AccountTokenCallback cb; 51 52 /** 53 * Closure for @a cb. 54 */ 55 void *cb_cls; 56 57 }; 58 59 60 /** 61 * Function called when we're done processing the 62 * HTTP /account/$ACC/token request. 63 * 64 * @param cls the `struct TALER_BANK_AccountTokenHandle` 65 * @param response_code HTTP response code, 0 on error 66 * @param response parsed JSON result, NULL on error 67 */ 68 static void 69 handle_account_token_finished (void *cls, 70 long response_code, 71 const void *response) 72 { 73 struct TALER_BANK_AccountTokenHandle *aai = cls; 74 const json_t *j = response; 75 struct TALER_BANK_AccountTokenResponse ir = { 76 .http_status = response_code, 77 .response = response 78 }; 79 80 aai->job = NULL; 81 switch (response_code) 82 { 83 case 0: 84 ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 85 break; 86 case MHD_HTTP_OK: 87 { 88 struct GNUNET_JSON_Specification spec[] = { 89 GNUNET_JSON_spec_string ("access_token", 90 &ir.details.ok.access_token), 91 GNUNET_JSON_spec_timestamp ("expiration", 92 &ir.details.ok.expiration), 93 GNUNET_JSON_spec_end () 94 }; 95 96 if (GNUNET_OK != 97 GNUNET_JSON_parse (j, 98 spec, 99 NULL, NULL)) 100 { 101 GNUNET_break_op (0); 102 ir.http_status = 0; 103 ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 104 break; 105 } 106 } 107 break; 108 case MHD_HTTP_BAD_REQUEST: 109 /* This should never happen, either us or the bank is buggy 110 (or API version conflict); just pass JSON reply to the application */ 111 GNUNET_break_op (0); 112 ir.ec = TALER_JSON_get_error_code (j); 113 break; 114 case MHD_HTTP_FORBIDDEN: 115 /* Access denied */ 116 ir.ec = TALER_JSON_get_error_code (j); 117 break; 118 case MHD_HTTP_UNAUTHORIZED: 119 /* Nothing really to verify, bank says the password is invalid; we should 120 pass the JSON reply to the application */ 121 ir.ec = TALER_JSON_get_error_code (j); 122 break; 123 case MHD_HTTP_NOT_FOUND: 124 /* Nothing really to verify, maybe account really does not exist. 125 We should pass the JSON reply to the application */ 126 ir.ec = TALER_JSON_get_error_code (j); 127 break; 128 case MHD_HTTP_INTERNAL_SERVER_ERROR: 129 /* Server had an internal issue; we should retry, but this API 130 leaves this to the application */ 131 ir.ec = TALER_JSON_get_error_code (j); 132 break; 133 default: 134 /* unexpected response code */ 135 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 136 "Unexpected response code %u\n", 137 (unsigned int) response_code); 138 GNUNET_break (0); 139 ir.ec = TALER_JSON_get_error_code (j); 140 break; 141 } 142 aai->cb (aai->cb_cls, 143 &ir); 144 TALER_BANK_account_token_cancel (aai); 145 } 146 147 148 /** 149 * Convert @a scope to string. 150 * 151 * @param scope a scope 152 * @return string encoding of the scope 153 */ 154 static const char * 155 scope_to_string (enum TALER_BANK_TokenScope scope) 156 { 157 switch (scope) 158 { 159 case TALER_BANK_TOKEN_SCOPE_READONLY: 160 return "readonly"; 161 case TALER_BANK_TOKEN_SCOPE_READWRITE: 162 return "readwrite"; 163 case TALER_BANK_TOKEN_SCOPE_REVENUE: 164 return "revenue"; 165 case TALER_BANK_TOKEN_SCOPE_WIREGATEWAY: 166 return "wiregateway"; 167 } 168 GNUNET_break (0); 169 return NULL; 170 } 171 172 173 struct TALER_BANK_AccountTokenHandle * 174 TALER_BANK_account_token ( 175 struct GNUNET_CURL_Context *ctx, 176 const struct TALER_BANK_AuthenticationData *auth, 177 const char *account_name, 178 enum TALER_BANK_TokenScope scope, 179 bool refreshable, 180 const char *description, 181 struct GNUNET_TIME_Relative duration, 182 TALER_BANK_AccountTokenCallback res_cb, 183 void *res_cb_cls) 184 { 185 struct TALER_BANK_AccountTokenHandle *ath; 186 json_t *token_req; 187 CURL *eh; 188 189 token_req = GNUNET_JSON_PACK ( 190 GNUNET_JSON_pack_string ("scope", 191 scope_to_string (scope)), 192 GNUNET_JSON_pack_allow_null ( 193 GNUNET_JSON_pack_string ("description", 194 description)), 195 GNUNET_JSON_pack_allow_null ( 196 GNUNET_JSON_pack_time_rel ("duration", 197 duration)), 198 GNUNET_JSON_pack_allow_null ( 199 GNUNET_JSON_pack_bool ("refreshable", 200 refreshable))); 201 if (NULL == token_req) 202 { 203 GNUNET_break (0); 204 return NULL; 205 } 206 ath = GNUNET_new (struct TALER_BANK_AccountTokenHandle); 207 ath->cb = res_cb; 208 ath->cb_cls = res_cb_cls; 209 ath->request_url = TALER_url_join (auth->core_bank_url, 210 "token", 211 NULL); 212 if (NULL == ath->request_url) 213 { 214 GNUNET_free (ath); 215 json_decref (token_req); 216 return NULL; 217 } 218 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 219 "Requesting access token at `%s'\n", 220 ath->request_url); 221 eh = curl_easy_init (); 222 if ( (NULL == eh) || 223 (GNUNET_OK != 224 TALER_BANK_setup_auth_ (eh, 225 auth)) || 226 (CURLE_OK != 227 curl_easy_setopt (eh, 228 CURLOPT_URL, 229 ath->request_url)) || 230 (GNUNET_OK != 231 TALER_curl_easy_post (&ath->post_ctx, 232 eh, 233 token_req)) ) 234 { 235 GNUNET_break (0); 236 TALER_BANK_account_token_cancel (ath); 237 if (NULL != eh) 238 curl_easy_cleanup (eh); 239 json_decref (token_req); 240 return NULL; 241 } 242 json_decref (token_req); 243 ath->job = GNUNET_CURL_job_add2 (ctx, 244 eh, 245 ath->post_ctx.headers, 246 &handle_account_token_finished, 247 ath); 248 GNUNET_assert (NULL != ath->job); 249 return ath; 250 } 251 252 253 void 254 TALER_BANK_account_token_cancel ( 255 struct TALER_BANK_AccountTokenHandle *ath) 256 { 257 if (NULL != ath->job) 258 { 259 GNUNET_CURL_job_cancel (ath->job); 260 ath->job = NULL; 261 } 262 TALER_curl_easy_post_finished (&ath->post_ctx); 263 GNUNET_free (ath->request_url); 264 GNUNET_free (ath); 265 } 266 267 268 /* end of bank_api_account_token.c */