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