aboutsummaryrefslogtreecommitdiff
path: root/src/restclient/anastasis_api_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/restclient/anastasis_api_config.c')
-rw-r--r--src/restclient/anastasis_api_config.c317
1 files changed, 317 insertions, 0 deletions
diff --git a/src/restclient/anastasis_api_config.c b/src/restclient/anastasis_api_config.c
new file mode 100644
index 0000000..cf0846b
--- /dev/null
+++ b/src/restclient/anastasis_api_config.c
@@ -0,0 +1,317 @@
1/*
2 This file is part of Anastasis
3 Copyright (C) 2020, 2021 Taler Systems SA
4
5 Anastasis 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 3, or (at your option) any later version.
8
9 Anastasis 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 Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file lib/anastasis_api_config.c
18 * @brief Implementation of the /config GET
19 * @author Christian Grothoff
20 * @author Dennis Neufeld
21 * @author Dominik Meister
22 */
23#include "platform.h"
24#include <curl/curl.h>
25#include <microhttpd.h> /* just for HTTP status codes */
26#include "anastasis_service.h"
27#include "anastasis_api_curl_defaults.h"
28#include <gnunet/gnunet_json_lib.h>
29#include <taler/taler_json_lib.h>
30
31
32/**
33 * Which version of the Taler protocol is implemented
34 * by this library? Used to determine compatibility.
35 */
36#define ANASTASIS_PROTOCOL_CURRENT 0
37
38/**
39 * How many versions are we backwards compatible with?
40 */
41#define ANASTASIS_PROTOCOL_AGE 0
42
43
44struct ANASTASIS_ConfigOperation
45{
46 /**
47 * The url for this request.
48 */
49 char *url;
50
51 /**
52 * Handle for the request.
53 */
54 struct GNUNET_CURL_Job *job;
55
56 /**
57 * Reference to the execution context.
58 */
59 struct GNUNET_CURL_Context *ctx;
60
61 /**
62 * The callback to pass the backend response to
63 */
64 ANASTASIS_ConfigCallback cb;
65
66 /**
67 * Closure for @a cb.
68 */
69 void *cb_cls;
70
71};
72
73
74/**
75 * Function called when we're done processing the
76 * HTTP /config request.
77 *
78 * @param cls the `struct ANASTASIS_ConfigOperation`
79 * @param response_code HTTP response code, 0 on error
80 * @param response parsed JSON result, NULL on error
81 */
82static void
83handle_config_finished (void *cls,
84 long response_code,
85 const void *response)
86{
87 struct ANASTASIS_ConfigOperation *co = cls;
88 const json_t *json = response;
89
90 co->job = NULL;
91 switch (response_code)
92 {
93 case 0:
94 /* Hard error */
95 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
96 "Backend `%s' failed to respond to GET /config\n",
97 co->url);
98 break;
99 case MHD_HTTP_OK:
100 {
101 const char *name;
102 struct ANASTASIS_Config acfg;
103 json_t *methods;
104 struct GNUNET_JSON_Specification spec[] = {
105 GNUNET_JSON_spec_string ("name",
106 &name),
107 GNUNET_JSON_spec_string ("business_name",
108 &acfg.business_name),
109 GNUNET_JSON_spec_string ("version",
110 &acfg.version),
111 GNUNET_JSON_spec_string ("currency",
112 &acfg.currency),
113 GNUNET_JSON_spec_json ("methods",
114 &methods),
115 GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes",
116 &acfg.storage_limit_in_megabytes),
117 TALER_JSON_spec_amount_any ("annual_fee",
118 &acfg.annual_fee),
119 TALER_JSON_spec_amount_any ("truth_upload_fee",
120 &acfg.truth_upload_fee),
121 TALER_JSON_spec_amount_any ("liability_limit",
122 &acfg.liability_limit),
123 GNUNET_JSON_spec_fixed_auto ("server_salt",
124 &acfg.salt),
125 GNUNET_JSON_spec_end ()
126 };
127
128 if (GNUNET_OK !=
129 GNUNET_JSON_parse (json,
130 spec,
131 NULL, NULL))
132 {
133 GNUNET_break_op (0);
134 response_code = 0;
135 break;
136 }
137 if (0 != strcmp (name,
138 "anastasis"))
139 {
140 GNUNET_JSON_parse_free (spec);
141 response_code = 0;
142 break;
143 }
144 {
145 unsigned int age;
146 unsigned int revision;
147 unsigned int current;
148 char dummy;
149
150 if (3 != sscanf (acfg.version,
151 "%u:%u:%u%c",
152 &current,
153 &revision,
154 &age,
155 &dummy))
156 {
157 GNUNET_break_op (0);
158 response_code = 0;
159 GNUNET_JSON_parse_free (spec);
160 break;
161 }
162 if ( (ANASTASIS_PROTOCOL_CURRENT < current) &&
163 (ANASTASIS_PROTOCOL_CURRENT < current - age) )
164 {
165 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
166 "Provider protocol version too new\n");
167 response_code = 0;
168 GNUNET_JSON_parse_free (spec);
169 break;
170 }
171 if ( (ANASTASIS_PROTOCOL_CURRENT > current) &&
172 (ANASTASIS_PROTOCOL_CURRENT - ANASTASIS_PROTOCOL_AGE > current) )
173 {
174 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
175 "Provider protocol version too old\n");
176 GNUNET_break_op (0);
177 response_code = 0;
178 GNUNET_JSON_parse_free (spec);
179 break;
180 }
181 }
182 if ( (GNUNET_OK !=
183 TALER_amount_cmp_currency (&acfg.liability_limit,
184 &acfg.annual_fee)) ||
185 (0 !=
186 strcasecmp (acfg.currency,
187 acfg.annual_fee.currency)) )
188 {
189 GNUNET_break_op (0);
190 GNUNET_JSON_parse_free (spec);
191 response_code = 0;
192 break;
193 }
194
195 if (! json_is_array (methods))
196 {
197 GNUNET_break_op (0);
198 GNUNET_JSON_parse_free (spec);
199 response_code = 0;
200 break;
201 }
202 acfg.methods_length = json_array_size (methods);
203 {
204 struct ANASTASIS_AuthorizationMethodConfig mcfg[GNUNET_NZL (
205 acfg.methods_length)];
206
207 for (unsigned int i = 0; i<acfg.methods_length; i++)
208 {
209 struct ANASTASIS_AuthorizationMethodConfig *m = &mcfg[i];
210 struct GNUNET_JSON_Specification spec[] = {
211 GNUNET_JSON_spec_string ("type",
212 &m->type),
213 TALER_JSON_spec_amount_any ("cost",
214 &m->usage_fee),
215 GNUNET_JSON_spec_end ()
216 };
217
218 if ( (GNUNET_OK !=
219 GNUNET_JSON_parse (json_array_get (methods,
220 i),
221 spec,
222 NULL, NULL)) ||
223 (0 !=
224 strcasecmp (m->usage_fee.currency,
225 acfg.currency)) )
226 {
227 GNUNET_break_op (0);
228 GNUNET_JSON_parse_free (spec);
229 response_code = 0;
230 goto end;
231 }
232 }
233 acfg.methods = mcfg;
234 co->cb (co->cb_cls,
235 MHD_HTTP_OK,
236 &acfg);
237 GNUNET_JSON_parse_free (spec);
238 ANASTASIS_config_cancel (co);
239 return;
240 }
241 }
242 case MHD_HTTP_BAD_REQUEST:
243 /* This should never happen, either us or the anastasis server is buggy
244 (or API version conflict); just pass JSON reply to the application */
245 break;
246 case MHD_HTTP_NOT_FOUND:
247 /* Nothing really to verify */
248 break;
249 case MHD_HTTP_INTERNAL_SERVER_ERROR:
250 /* Server had an internal issue; we should retry, but this API
251 leaves this to the application */
252 break;
253 default:
254 /* unexpected response code */
255 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
256 "Unexpected response code %u\n",
257 (unsigned int) response_code);
258 GNUNET_break_op (0);
259 break;
260 }
261end:
262 co->cb (co->cb_cls,
263 response_code,
264 NULL);
265 ANASTASIS_config_cancel (co);
266}
267
268
269struct ANASTASIS_ConfigOperation *
270ANASTASIS_get_config (struct GNUNET_CURL_Context *ctx,
271 const char *base_url,
272 ANASTASIS_ConfigCallback cb,
273 void *cb_cls)
274{
275 struct ANASTASIS_ConfigOperation *co;
276
277 co = GNUNET_new (struct ANASTASIS_ConfigOperation);
278 co->url = TALER_url_join (base_url,
279 "config",
280 NULL);
281 co->ctx = ctx;
282 co->cb = cb;
283 co->cb_cls = cb_cls;
284 {
285 CURL *eh;
286
287 eh = ANASTASIS_curl_easy_get_ (co->url);
288 co->job = GNUNET_CURL_job_add2 (ctx,
289 eh,
290 GNUNET_NO,
291 &handle_config_finished,
292 co);
293 }
294 if (NULL == co->job)
295 {
296 GNUNET_free (co->url);
297 GNUNET_free (co);
298 return NULL;
299 }
300 return co;
301}
302
303
304void
305ANASTASIS_config_cancel (struct ANASTASIS_ConfigOperation *co)
306{
307 if (NULL != co->job)
308 {
309 GNUNET_CURL_job_cancel (co->job);
310 co->job = NULL;
311 }
312 GNUNET_free (co->url);
313 GNUNET_free (co);
314}
315
316
317/* end of anastasis_api_config.c */