Line data Source code
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 0 : handle_account_token_finished (void *cls,
69 : long response_code,
70 : const void *response)
71 : {
72 0 : struct TALER_BANK_AccountTokenHandle *aai = cls;
73 0 : const json_t *j = response;
74 0 : struct TALER_BANK_AccountTokenResponse ir = {
75 : .http_status = response_code,
76 : .response = response
77 : };
78 :
79 0 : aai->job = NULL;
80 0 : switch (response_code)
81 : {
82 0 : case 0:
83 0 : ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
84 0 : break;
85 0 : case MHD_HTTP_OK:
86 : {
87 : struct GNUNET_JSON_Specification spec[] = {
88 0 : GNUNET_JSON_spec_string ("access_token",
89 : &ir.details.ok.access_token),
90 0 : GNUNET_JSON_spec_timestamp ("expiration",
91 : &ir.details.ok.expiration),
92 0 : GNUNET_JSON_spec_end ()
93 : };
94 :
95 0 : if (GNUNET_OK !=
96 0 : GNUNET_JSON_parse (j,
97 : spec,
98 : NULL, NULL))
99 : {
100 0 : GNUNET_break_op (0);
101 0 : ir.http_status = 0;
102 0 : ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
103 0 : break;
104 : }
105 : }
106 0 : break;
107 0 : 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 0 : GNUNET_break_op (0);
111 0 : ir.ec = TALER_JSON_get_error_code (j);
112 0 : break;
113 0 : case MHD_HTTP_FORBIDDEN:
114 : /* Access denied */
115 0 : ir.ec = TALER_JSON_get_error_code (j);
116 0 : break;
117 0 : 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 0 : ir.ec = TALER_JSON_get_error_code (j);
121 0 : break;
122 0 : 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 0 : ir.ec = TALER_JSON_get_error_code (j);
126 0 : break;
127 0 : 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 0 : ir.ec = TALER_JSON_get_error_code (j);
131 0 : break;
132 0 : default:
133 : /* unexpected response code */
134 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
135 : "Unexpected response code %u\n",
136 : (unsigned int) response_code);
137 0 : GNUNET_break (0);
138 0 : ir.ec = TALER_JSON_get_error_code (j);
139 0 : break;
140 : }
141 0 : aai->cb (aai->cb_cls,
142 : &ir);
143 0 : TALER_BANK_account_token_cancel (aai);
144 0 : }
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 0 : scope_to_string (enum TALER_BANK_TokenScope scope)
155 : {
156 0 : switch (scope)
157 : {
158 0 : case TALER_BANK_TOKEN_SCOPE_READONLY:
159 0 : return "readonly";
160 0 : case TALER_BANK_TOKEN_SCOPE_READWRITE:
161 0 : return "readwrite";
162 0 : case TALER_BANK_TOKEN_SCOPE_REVENUE:
163 0 : return "revenue";
164 0 : case TALER_BANK_TOKEN_SCOPE_WIREGATEWAY:
165 0 : return "wiregateway";
166 : }
167 0 : GNUNET_break (0);
168 0 : return NULL;
169 : }
170 :
171 :
172 : struct TALER_BANK_AccountTokenHandle *
173 0 : 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 0 : 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 0 : ath = GNUNET_new (struct TALER_BANK_AccountTokenHandle);
200 0 : ath->cb = res_cb;
201 0 : ath->cb_cls = res_cb_cls;
202 0 : ath->request_url = TALER_url_join (auth->core_bank_url,
203 : "token",
204 : NULL);
205 0 : if (NULL == ath->request_url)
206 : {
207 0 : GNUNET_free (ath);
208 0 : json_decref (token_req);
209 0 : return NULL;
210 : }
211 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
212 : "Requesting access token at `%s'\n",
213 : ath->request_url);
214 0 : eh = curl_easy_init ();
215 0 : if ( (NULL == eh) ||
216 : (GNUNET_OK !=
217 0 : TALER_BANK_setup_auth_ (eh,
218 0 : auth)) ||
219 : (CURLE_OK !=
220 0 : curl_easy_setopt (eh,
221 : CURLOPT_URL,
222 0 : ath->request_url)) ||
223 : (GNUNET_OK !=
224 0 : TALER_curl_easy_post (&ath->post_ctx,
225 : eh,
226 : token_req)) )
227 : {
228 0 : GNUNET_break (0);
229 0 : TALER_BANK_account_token_cancel (ath);
230 0 : if (NULL != eh)
231 0 : curl_easy_cleanup (eh);
232 0 : json_decref (token_req);
233 0 : return NULL;
234 : }
235 0 : json_decref (token_req);
236 0 : ath->job = GNUNET_CURL_job_add2 (ctx,
237 : eh,
238 0 : ath->post_ctx.headers,
239 : &handle_account_token_finished,
240 : ath);
241 0 : if (NULL == ath->job)
242 : {
243 0 : GNUNET_break (0);
244 0 : curl_easy_cleanup (eh);
245 0 : TALER_BANK_account_token_cancel (ath);
246 0 : return NULL;
247 : }
248 0 : return ath;
249 : }
250 :
251 :
252 : void
253 0 : TALER_BANK_account_token_cancel (
254 : struct TALER_BANK_AccountTokenHandle *ath)
255 : {
256 0 : if (NULL != ath->job)
257 : {
258 0 : GNUNET_CURL_job_cancel (ath->job);
259 0 : ath->job = NULL;
260 : }
261 0 : TALER_curl_easy_post_finished (&ath->post_ctx);
262 0 : GNUNET_free (ath->request_url);
263 0 : GNUNET_free (ath);
264 0 : }
265 :
266 :
267 : /* end of bank_api_account_token.c */
|