Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2017, 2020 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU Lesser General Public License as published by the Free Software
7 : Foundation; either version 2.1, 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 Lesser General Public License for more details.
12 :
13 : You should have received a copy of the GNU Lesser General Public License along with
14 : TALER; see the file COPYING.LGPL. If not, see
15 : <http://www.gnu.org/licenses/>
16 : */
17 : /**
18 : * @file merchant_api_get_transfers.c
19 : * @brief Implementation of the GET /transfers request of the merchant's HTTP API
20 : * @author Marcello Stanisci
21 : * @author Christian Grothoff
22 : */
23 : #include "platform.h"
24 : #include <curl/curl.h>
25 : #include <jansson.h>
26 : #include <microhttpd.h> /* just for HTTP status codes */
27 : #include <gnunet/gnunet_util_lib.h>
28 : #include <gnunet/gnunet_curl_lib.h>
29 : #include "taler_merchant_service.h"
30 : #include "merchant_api_curl_defaults.h"
31 : #include <taler/taler_json_lib.h>
32 : #include <taler/taler_signatures.h>
33 :
34 :
35 : /**
36 : * @brief A Handle for tracking wire transfers.
37 : */
38 : struct TALER_MERCHANT_GetTransfersHandle
39 : {
40 :
41 : /**
42 : * The url for this request.
43 : */
44 : char *url;
45 :
46 : /**
47 : * Handle for the request.
48 : */
49 : struct GNUNET_CURL_Job *job;
50 :
51 : /**
52 : * Function to call with the result.
53 : */
54 : TALER_MERCHANT_GetTransfersCallback cb;
55 :
56 : /**
57 : * Closure for @a cb.
58 : */
59 : void *cb_cls;
60 :
61 : /**
62 : * Reference to the execution context.
63 : */
64 : struct GNUNET_CURL_Context *ctx;
65 : };
66 :
67 :
68 : /**
69 : * Function called when we're done processing the
70 : * HTTP GET /transfers request.
71 : *
72 : * @param cls the `struct TALER_MERCHANT_GetTransfersHandle`
73 : * @param response_code HTTP response code, 0 on error
74 : * @param response response body, NULL if not in JSON
75 : */
76 : static void
77 0 : handle_transfers_get_finished (void *cls,
78 : long response_code,
79 : const void *response)
80 : {
81 0 : struct TALER_MERCHANT_GetTransfersHandle *gth = cls;
82 0 : const json_t *json = response;
83 0 : struct TALER_MERCHANT_HttpResponse hr = {
84 0 : .http_status = (unsigned int) response_code,
85 : .reply = json
86 : };
87 :
88 0 : gth->job = NULL;
89 0 : switch (response_code)
90 : {
91 0 : case 0:
92 0 : hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
93 0 : break;
94 0 : case MHD_HTTP_OK:
95 : {
96 : json_t *transfers;
97 : struct GNUNET_JSON_Specification spec[] = {
98 0 : GNUNET_JSON_spec_json ("transfers",
99 : &transfers),
100 0 : GNUNET_JSON_spec_end ()
101 : };
102 :
103 0 : if (GNUNET_OK !=
104 0 : GNUNET_JSON_parse (json,
105 : spec,
106 : NULL, NULL))
107 : {
108 0 : GNUNET_break_op (0);
109 0 : hr.http_status = 0;
110 0 : hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
111 0 : break;
112 : }
113 : else
114 : {
115 : size_t tds_length;
116 : struct TALER_MERCHANT_TransferData *tds;
117 : json_t *transfer;
118 : unsigned int i;
119 : bool ok;
120 :
121 0 : if (! json_is_array (transfers))
122 : {
123 0 : GNUNET_break_op (0);
124 0 : GNUNET_JSON_parse_free (spec);
125 0 : hr.http_status = 0;
126 0 : hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
127 0 : break;
128 : }
129 0 : tds_length = json_array_size (transfers);
130 0 : tds = GNUNET_new_array (tds_length,
131 : struct TALER_MERCHANT_TransferData);
132 0 : ok = true;
133 0 : json_array_foreach (transfers, i, transfer) {
134 0 : struct TALER_MERCHANT_TransferData *td = &tds[i];
135 : struct GNUNET_JSON_Specification ispec[] = {
136 0 : TALER_JSON_spec_amount_any ("credit_amount",
137 : &td->credit_amount),
138 0 : GNUNET_JSON_spec_fixed_auto ("wtid",
139 : &td->wtid),
140 0 : GNUNET_JSON_spec_string ("payto_uri",
141 : &td->payto_uri),
142 0 : GNUNET_JSON_spec_string ("exchange_url",
143 : &td->exchange_url),
144 0 : GNUNET_JSON_spec_uint64 ("transfer_serial_id",
145 : &td->credit_serial),
146 0 : GNUNET_JSON_spec_mark_optional (
147 : GNUNET_JSON_spec_timestamp ("execution_time",
148 : &td->execution_time),
149 : NULL),
150 0 : GNUNET_JSON_spec_mark_optional (
151 : GNUNET_JSON_spec_bool ("verified",
152 : &td->verified),
153 : NULL),
154 0 : GNUNET_JSON_spec_mark_optional (
155 : GNUNET_JSON_spec_bool ("confirmed",
156 : &td->confirmed),
157 : NULL),
158 0 : GNUNET_JSON_spec_end ()
159 : };
160 :
161 0 : if (GNUNET_OK !=
162 0 : GNUNET_JSON_parse (transfer,
163 : ispec,
164 : NULL, NULL))
165 : {
166 0 : GNUNET_break_op (0);
167 0 : ok = false;
168 0 : break;
169 : }
170 : }
171 :
172 0 : if (! ok)
173 : {
174 0 : GNUNET_break_op (0);
175 0 : GNUNET_free (tds);
176 0 : GNUNET_JSON_parse_free (spec);
177 0 : hr.http_status = 0;
178 0 : hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
179 0 : break;
180 : }
181 0 : gth->cb (gth->cb_cls,
182 : &hr,
183 : tds_length,
184 : tds);
185 0 : GNUNET_free (tds);
186 0 : GNUNET_JSON_parse_free (spec);
187 0 : TALER_MERCHANT_transfers_get_cancel (gth);
188 0 : return;
189 : }
190 : }
191 0 : case MHD_HTTP_UNAUTHORIZED:
192 0 : hr.ec = TALER_JSON_get_error_code (json);
193 0 : hr.hint = TALER_JSON_get_error_hint (json);
194 : /* Nothing really to verify, merchant says we need to authenticate. */
195 0 : break;
196 0 : case MHD_HTTP_NOT_FOUND:
197 : /* Nothing really to verify, this should never
198 : happen, we should pass the JSON reply to the application */
199 0 : hr.ec = TALER_JSON_get_error_code (json);
200 0 : hr.hint = TALER_JSON_get_error_hint (json);
201 0 : break;
202 0 : case MHD_HTTP_INTERNAL_SERVER_ERROR:
203 : /* Server had an internal issue; we should retry, but this API
204 : leaves this to the application */
205 0 : hr.ec = TALER_JSON_get_error_code (json);
206 0 : hr.hint = TALER_JSON_get_error_hint (json);
207 0 : break;
208 0 : default:
209 : /* unexpected response code */
210 0 : GNUNET_break_op (0);
211 0 : TALER_MERCHANT_parse_error_details_ (json,
212 : response_code,
213 : &hr);
214 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
215 : "Unexpected response code %u/%d\n",
216 : (unsigned int) response_code,
217 : (int) hr.ec);
218 0 : response_code = 0;
219 0 : break;
220 : }
221 0 : gth->cb (gth->cb_cls,
222 : &hr,
223 : 0,
224 : NULL);
225 0 : TALER_MERCHANT_transfers_get_cancel (gth);
226 : }
227 :
228 :
229 : struct TALER_MERCHANT_GetTransfersHandle *
230 0 : TALER_MERCHANT_transfers_get (
231 : struct GNUNET_CURL_Context *ctx,
232 : const char *backend_url,
233 : const char *payto_uri,
234 : const struct GNUNET_TIME_Timestamp before,
235 : const struct GNUNET_TIME_Timestamp after,
236 : int64_t limit,
237 : uint64_t offset,
238 : enum TALER_EXCHANGE_YesNoAll verified,
239 : TALER_MERCHANT_GetTransfersCallback cb,
240 : void *cb_cls)
241 : {
242 : struct TALER_MERCHANT_GetTransfersHandle *gth;
243 : CURL *eh;
244 0 : const char *verified_s = NULL;
245 : char limit_s[30];
246 : char offset_s[30];
247 : char *before_s;
248 : char *after_s;
249 :
250 0 : gth = GNUNET_new (struct TALER_MERCHANT_GetTransfersHandle);
251 0 : gth->ctx = ctx;
252 0 : gth->cb = cb;
253 0 : gth->cb_cls = cb_cls;
254 0 : verified_s = TALER_yna_to_string (verified);
255 0 : GNUNET_snprintf (limit_s,
256 : sizeof (limit_s),
257 : "%lld",
258 : (long long) limit);
259 0 : GNUNET_snprintf (offset_s,
260 : sizeof (offset_s),
261 : "%lld",
262 : (unsigned long long) offset);
263 0 : before_s = GNUNET_strdup (GNUNET_TIME_timestamp2s (before));
264 0 : after_s = GNUNET_strdup (GNUNET_TIME_timestamp2s (after));
265 0 : gth->url = TALER_url_join (backend_url,
266 : "private/transfers",
267 : "payto_uri",
268 : payto_uri,
269 : "verified",
270 : (TALER_EXCHANGE_YNA_ALL != verified)
271 : ? verified_s
272 : : NULL,
273 : "limit",
274 : 0 != limit
275 : ? limit_s
276 : : NULL,
277 : "offset",
278 0 : ((0 != offset) && (UINT64_MAX != offset))
279 : ? offset_s
280 : : NULL,
281 : "before",
282 0 : GNUNET_TIME_absolute_is_never (before.abs_time)
283 : ? NULL
284 : : before_s,
285 : "after",
286 0 : GNUNET_TIME_absolute_is_zero (after.abs_time)
287 : ? NULL
288 : : after_s,
289 : NULL);
290 0 : GNUNET_free (before_s);
291 0 : GNUNET_free (after_s);
292 0 : if (NULL == gth->url)
293 : {
294 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
295 : "Could not construct request URL.\n");
296 0 : GNUNET_free (gth);
297 0 : return NULL;
298 : }
299 0 : eh = TALER_MERCHANT_curl_easy_get_ (gth->url);
300 0 : gth->job = GNUNET_CURL_job_add (ctx,
301 : eh,
302 : &handle_transfers_get_finished,
303 : gth);
304 0 : return gth;
305 : }
306 :
307 :
308 : void
309 0 : TALER_MERCHANT_transfers_get_cancel (
310 : struct TALER_MERCHANT_GetTransfersHandle *gth)
311 : {
312 0 : if (NULL != gth->job)
313 : {
314 0 : GNUNET_CURL_job_cancel (gth->job);
315 0 : gth->job = NULL;
316 : }
317 0 : GNUNET_free (gth->url);
318 0 : GNUNET_free (gth);
319 0 : }
320 :
321 :
322 : /* end of merchant_api_get_transfers.c */
|