bank_api_account_token.c (7263B)
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 enum TALER_BANK_TokenScope scope, 177 bool refreshable, 178 const char *description, 179 struct GNUNET_TIME_Relative duration, 180 TALER_BANK_AccountTokenCallback res_cb, 181 void *res_cb_cls) 182 { 183 struct TALER_BANK_AccountTokenHandle *ath; 184 json_t *token_req; 185 CURL *eh; 186 187 token_req = GNUNET_JSON_PACK ( 188 GNUNET_JSON_pack_string ("scope", 189 scope_to_string (scope)), 190 GNUNET_JSON_pack_allow_null ( 191 GNUNET_JSON_pack_string ("description", 192 description)), 193 GNUNET_JSON_pack_allow_null ( 194 GNUNET_JSON_pack_time_rel ("duration", 195 duration)), 196 GNUNET_JSON_pack_allow_null ( 197 GNUNET_JSON_pack_bool ("refreshable", 198 refreshable))); 199 ath = GNUNET_new (struct TALER_BANK_AccountTokenHandle); 200 ath->cb = res_cb; 201 ath->cb_cls = res_cb_cls; 202 ath->request_url = TALER_url_join (auth->core_bank_url, 203 "token", 204 NULL); 205 if (NULL == ath->request_url) 206 { 207 GNUNET_free (ath); 208 json_decref (token_req); 209 return NULL; 210 } 211 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 212 "Requesting access token at `%s'\n", 213 ath->request_url); 214 eh = curl_easy_init (); 215 if ( (NULL == eh) || 216 (GNUNET_OK != 217 TALER_BANK_setup_auth_ (eh, 218 auth)) || 219 (CURLE_OK != 220 curl_easy_setopt (eh, 221 CURLOPT_URL, 222 ath->request_url)) || 223 (GNUNET_OK != 224 TALER_curl_easy_post (&ath->post_ctx, 225 eh, 226 token_req)) ) 227 { 228 GNUNET_break (0); 229 TALER_BANK_account_token_cancel (ath); 230 if (NULL != eh) 231 curl_easy_cleanup (eh); 232 json_decref (token_req); 233 return NULL; 234 } 235 json_decref (token_req); 236 ath->job = GNUNET_CURL_job_add2 (ctx, 237 eh, 238 ath->post_ctx.headers, 239 &handle_account_token_finished, 240 ath); 241 GNUNET_assert (NULL != ath->job); 242 return ath; 243 } 244 245 246 void 247 TALER_BANK_account_token_cancel ( 248 struct TALER_BANK_AccountTokenHandle *ath) 249 { 250 if (NULL != ath->job) 251 { 252 GNUNET_CURL_job_cancel (ath->job); 253 ath->job = NULL; 254 } 255 TALER_curl_easy_post_finished (&ath->post_ctx); 256 GNUNET_free (ath->request_url); 257 GNUNET_free (ath); 258 } 259 260 261 /* end of bank_api_account_token.c */