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 : 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 0 : 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 0 : if (NULL == token_req)
201 : {
202 0 : GNUNET_break (0);
203 0 : return NULL;
204 : }
205 0 : ath = GNUNET_new (struct TALER_BANK_AccountTokenHandle);
206 0 : ath->cb = res_cb;
207 0 : ath->cb_cls = res_cb_cls;
208 0 : ath->request_url = TALER_url_join (auth->core_bank_url,
209 : "token",
210 : NULL);
211 0 : if (NULL == ath->request_url)
212 : {
213 0 : GNUNET_free (ath);
214 0 : json_decref (token_req);
215 0 : return NULL;
216 : }
217 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
218 : "Requesting access token at `%s'\n",
219 : ath->request_url);
220 0 : eh = curl_easy_init ();
221 0 : if ( (NULL == eh) ||
222 : (GNUNET_OK !=
223 0 : TALER_BANK_setup_auth_ (eh,
224 0 : auth)) ||
225 : (CURLE_OK !=
226 0 : curl_easy_setopt (eh,
227 : CURLOPT_URL,
228 0 : ath->request_url)) ||
229 : (GNUNET_OK !=
230 0 : TALER_curl_easy_post (&ath->post_ctx,
231 : eh,
232 : token_req)) )
233 : {
234 0 : GNUNET_break (0);
235 0 : TALER_BANK_account_token_cancel (ath);
236 0 : if (NULL != eh)
237 0 : curl_easy_cleanup (eh);
238 0 : json_decref (token_req);
239 0 : return NULL;
240 : }
241 0 : json_decref (token_req);
242 0 : ath->job = GNUNET_CURL_job_add2 (ctx,
243 : eh,
244 0 : ath->post_ctx.headers,
245 : &handle_account_token_finished,
246 : ath);
247 0 : GNUNET_assert (NULL != ath->job);
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 */
|