Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2022-2026 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-private-accounts-new.c
19 : * @brief Implementation of the GET /private/accounts request
20 : * @author Christian Grothoff
21 : */
22 : #include "taler/platform.h"
23 : #include <curl/curl.h>
24 : #include <jansson.h>
25 : #include <microhttpd.h> /* just for HTTP status codes */
26 : #include <gnunet/gnunet_util_lib.h>
27 : #include <gnunet/gnunet_curl_lib.h>
28 : #include <taler/merchant/get-private-accounts.h>
29 : #include "merchant_api_curl_defaults.h"
30 : #include <taler/taler_json_lib.h>
31 :
32 : /**
33 : * Maximum number of accounts permitted.
34 : */
35 : #define MAX_ACCOUNTS 1024
36 :
37 :
38 : /**
39 : * Handle for a GET /private/accounts operation.
40 : */
41 : struct TALER_MERCHANT_GetPrivateAccountsHandle
42 : {
43 : /**
44 : * Base URL of the merchant backend.
45 : */
46 : char *base_url;
47 :
48 : /**
49 : * The full URL for this request.
50 : */
51 : char *url;
52 :
53 : /**
54 : * Handle for the request.
55 : */
56 : struct GNUNET_CURL_Job *job;
57 :
58 : /**
59 : * Function to call with the result.
60 : */
61 : TALER_MERCHANT_GetPrivateAccountsCallback cb;
62 :
63 : /**
64 : * Closure for @a cb.
65 : */
66 : TALER_MERCHANT_GET_PRIVATE_ACCOUNTS_RESULT_CLOSURE *cb_cls;
67 :
68 : /**
69 : * Reference to the execution context.
70 : */
71 : struct GNUNET_CURL_Context *ctx;
72 : };
73 :
74 :
75 : /**
76 : * Parse account information from @a ia.
77 : *
78 : * @param ia JSON array (or NULL!) with account data
79 : * @param[in] tgr partially filled response
80 : * @param gah operation handle
81 : * @return #GNUNET_OK on success
82 : */
83 : static enum GNUNET_GenericReturnValue
84 0 : parse_accounts (const json_t *ia,
85 : struct TALER_MERCHANT_GetPrivateAccountsResponse *tgr,
86 : struct TALER_MERCHANT_GetPrivateAccountsHandle *gah)
87 : {
88 0 : unsigned int accounts_len = (unsigned int) json_array_size (ia);
89 :
90 0 : if ( (json_array_size (ia) != (size_t) accounts_len) ||
91 : (accounts_len > MAX_ACCOUNTS) )
92 : {
93 0 : GNUNET_break (0);
94 0 : return GNUNET_SYSERR;
95 : }
96 0 : {
97 0 : struct TALER_MERCHANT_GetPrivateAccountsAccountEntry accounts[
98 0 : GNUNET_NZL (accounts_len)];
99 : size_t index;
100 : json_t *value;
101 :
102 0 : json_array_foreach (ia, index, value) {
103 0 : struct TALER_MERCHANT_GetPrivateAccountsAccountEntry *ae =
104 : &accounts[index];
105 : struct GNUNET_JSON_Specification spec[] = {
106 0 : TALER_JSON_spec_full_payto_uri ("payto_uri",
107 : &ae->payto_uri),
108 0 : GNUNET_JSON_spec_fixed_auto ("h_wire",
109 : &ae->h_wire),
110 0 : GNUNET_JSON_spec_bool ("active",
111 : &ae->active),
112 0 : GNUNET_JSON_spec_end ()
113 : };
114 :
115 0 : if (GNUNET_OK !=
116 0 : GNUNET_JSON_parse (value,
117 : spec,
118 : NULL, NULL))
119 : {
120 0 : GNUNET_break_op (0);
121 0 : return GNUNET_SYSERR;
122 : }
123 : }
124 0 : tgr->details.ok.accounts_length = accounts_len;
125 0 : tgr->details.ok.accounts = accounts;
126 0 : gah->cb (gah->cb_cls,
127 : tgr);
128 0 : gah->cb = NULL;
129 : }
130 0 : return GNUNET_OK;
131 : }
132 :
133 :
134 : /**
135 : * Function called when we're done processing the
136 : * HTTP GET /private/accounts request.
137 : *
138 : * @param cls the `struct TALER_MERCHANT_GetPrivateAccountsHandle`
139 : * @param response_code HTTP response code, 0 on error
140 : * @param response response body, NULL if not in JSON
141 : */
142 : static void
143 0 : handle_get_accounts_finished (void *cls,
144 : long response_code,
145 : const void *response)
146 : {
147 0 : struct TALER_MERCHANT_GetPrivateAccountsHandle *gah = cls;
148 0 : const json_t *json = response;
149 0 : struct TALER_MERCHANT_GetPrivateAccountsResponse tgr = {
150 0 : .hr.http_status = (unsigned int) response_code,
151 : .hr.reply = json
152 : };
153 :
154 0 : gah->job = NULL;
155 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
156 : "Got /private/accounts response with status code %u\n",
157 : (unsigned int) response_code);
158 0 : switch (response_code)
159 : {
160 0 : case MHD_HTTP_OK:
161 : {
162 : const json_t *accounts;
163 : struct GNUNET_JSON_Specification spec[] = {
164 0 : GNUNET_JSON_spec_array_const ("accounts",
165 : &accounts),
166 0 : GNUNET_JSON_spec_end ()
167 : };
168 :
169 0 : if (GNUNET_OK !=
170 0 : GNUNET_JSON_parse (json,
171 : spec,
172 : NULL, NULL))
173 : {
174 0 : tgr.hr.http_status = 0;
175 0 : tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
176 0 : break;
177 : }
178 0 : if (GNUNET_OK ==
179 0 : parse_accounts (accounts,
180 : &tgr,
181 : gah))
182 : {
183 0 : TALER_MERCHANT_get_private_accounts_cancel (gah);
184 0 : return;
185 : }
186 0 : tgr.hr.http_status = 0;
187 0 : tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
188 0 : break;
189 : }
190 0 : case MHD_HTTP_UNAUTHORIZED:
191 0 : tgr.hr.ec = TALER_JSON_get_error_code (json);
192 0 : tgr.hr.hint = TALER_JSON_get_error_hint (json);
193 0 : break;
194 0 : default:
195 0 : tgr.hr.ec = TALER_JSON_get_error_code (json);
196 0 : tgr.hr.hint = TALER_JSON_get_error_hint (json);
197 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
198 : "Unexpected response code %u/%d\n",
199 : (unsigned int) response_code,
200 : (int) tgr.hr.ec);
201 0 : break;
202 : }
203 0 : gah->cb (gah->cb_cls,
204 : &tgr);
205 0 : TALER_MERCHANT_get_private_accounts_cancel (gah);
206 : }
207 :
208 :
209 : struct TALER_MERCHANT_GetPrivateAccountsHandle *
210 0 : TALER_MERCHANT_get_private_accounts_create (
211 : struct GNUNET_CURL_Context *ctx,
212 : const char *url)
213 : {
214 : struct TALER_MERCHANT_GetPrivateAccountsHandle *gah;
215 :
216 0 : gah = GNUNET_new (struct TALER_MERCHANT_GetPrivateAccountsHandle);
217 0 : gah->ctx = ctx;
218 0 : gah->base_url = GNUNET_strdup (url);
219 0 : return gah;
220 : }
221 :
222 :
223 : enum TALER_ErrorCode
224 0 : TALER_MERCHANT_get_private_accounts_start (
225 : struct TALER_MERCHANT_GetPrivateAccountsHandle *gah,
226 : TALER_MERCHANT_GetPrivateAccountsCallback cb,
227 : TALER_MERCHANT_GET_PRIVATE_ACCOUNTS_RESULT_CLOSURE *cb_cls)
228 : {
229 : CURL *eh;
230 :
231 0 : gah->cb = cb;
232 0 : gah->cb_cls = cb_cls;
233 0 : gah->url = TALER_url_join (gah->base_url,
234 : "private/accounts",
235 : NULL);
236 0 : if (NULL == gah->url)
237 0 : return TALER_EC_GENERIC_CONFIGURATION_INVALID;
238 0 : eh = TALER_MERCHANT_curl_easy_get_ (gah->url);
239 0 : if (NULL == eh)
240 0 : return TALER_EC_GENERIC_CONFIGURATION_INVALID;
241 0 : gah->job = GNUNET_CURL_job_add (gah->ctx,
242 : eh,
243 : &handle_get_accounts_finished,
244 : gah);
245 0 : if (NULL == gah->job)
246 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
247 0 : return TALER_EC_NONE;
248 : }
249 :
250 :
251 : void
252 0 : TALER_MERCHANT_get_private_accounts_cancel (
253 : struct TALER_MERCHANT_GetPrivateAccountsHandle *gah)
254 : {
255 0 : if (NULL != gah->job)
256 : {
257 0 : GNUNET_CURL_job_cancel (gah->job);
258 0 : gah->job = NULL;
259 : }
260 0 : GNUNET_free (gah->url);
261 0 : GNUNET_free (gah->base_url);
262 0 : GNUNET_free (gah);
263 0 : }
264 :
265 :
266 : /* end of merchant_api_get-private-accounts-new.c */
|