Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2023 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 lib/auditor_api_get_config.c
19 : * @brief Implementation of /config for the auditor's HTTP API
20 : * @author Sree Harsha Totakura <sreeharsha@totakura.in>
21 : * @author Christian Grothoff
22 : */
23 : #include "platform.h"
24 : #include <microhttpd.h>
25 : #include <gnunet/gnunet_curl_lib.h>
26 : #include "taler_json_lib.h"
27 : #include "taler_auditor_service.h"
28 : #include "taler_signatures.h"
29 : #include "auditor_api_curl_defaults.h"
30 :
31 :
32 : /**
33 : * Which revision of the Taler auditor protocol is implemented
34 : * by this library? Used to determine compatibility.
35 : */
36 : #define TALER_PROTOCOL_CURRENT 1
37 :
38 : /**
39 : * How many revisions back are we compatible to?
40 : */
41 : #define TALER_PROTOCOL_AGE 0
42 :
43 :
44 : /**
45 : * Log error related to CURL operations.
46 : *
47 : * @param type log level
48 : * @param function which function failed to run
49 : * @param code what was the curl error code
50 : */
51 : #define CURL_STRERROR(type, function, code) \
52 : GNUNET_log (type, "Curl function `%s' has failed at `%s:%d' with error: %s", \
53 : function, __FILE__, __LINE__, curl_easy_strerror (code));
54 :
55 :
56 : /**
57 : * Handle for the get config request.
58 : */
59 : struct TALER_AUDITOR_GetConfigHandle
60 : {
61 : /**
62 : * The context of this handle
63 : */
64 : struct GNUNET_CURL_Context *ctx;
65 :
66 : /**
67 : * Function to call with the auditor's certification data,
68 : * NULL if this has already been done.
69 : */
70 : TALER_AUDITOR_ConfigCallback config_cb;
71 :
72 : /**
73 : * Closure to pass to @e config_cb.
74 : */
75 : void *config_cb_cls;
76 :
77 : /**
78 : * Data for the request to get the /config of a auditor,
79 : * NULL once we are past stage #MHS_INIT.
80 : */
81 : struct GNUNET_CURL_Job *vr;
82 :
83 : /**
84 : * The url for the @e vr job.
85 : */
86 : char *vr_url;
87 :
88 : };
89 :
90 :
91 : /* ***************** Internal /config fetching ************* */
92 :
93 : /**
94 : * Decode the JSON in @a resp_obj from the /config response and store the data
95 : * in the @a key_data.
96 : *
97 : * @param[in] resp_obj JSON object to parse
98 : * @param[in,out] vi where to store the results we decoded
99 : * @param[out] vc where to store config compatibility data
100 : * @return #TALER_EC_NONE on success
101 : */
102 : static enum TALER_ErrorCode
103 5 : decode_config_json (const json_t *resp_obj,
104 : struct TALER_AUDITOR_ConfigInformation *vi,
105 : enum TALER_AUDITOR_VersionCompatibility *vc)
106 : {
107 : struct TALER_JSON_ProtocolVersion pv;
108 : const char *ver;
109 : struct GNUNET_JSON_Specification spec[] = {
110 5 : TALER_JSON_spec_version ("version",
111 : &pv),
112 5 : GNUNET_JSON_spec_string ("version",
113 : &ver),
114 5 : GNUNET_JSON_spec_fixed_auto ("exchange_master_public_key",
115 : &vi->exchange_master_public_key),
116 5 : GNUNET_JSON_spec_fixed_auto ("auditor_public_key",
117 : &vi->auditor_pub),
118 5 : GNUNET_JSON_spec_end ()
119 : };
120 :
121 5 : if (JSON_OBJECT != json_typeof (resp_obj))
122 : {
123 0 : GNUNET_break_op (0);
124 0 : return TALER_EC_GENERIC_JSON_INVALID;
125 : }
126 : /* check the config */
127 5 : if (GNUNET_OK !=
128 5 : GNUNET_JSON_parse (resp_obj,
129 : spec,
130 : NULL, NULL))
131 : {
132 0 : GNUNET_break_op (0);
133 0 : return TALER_EC_GENERIC_JSON_INVALID;
134 : }
135 5 : vi->version = ver;
136 5 : *vc = TALER_AUDITOR_VC_MATCH;
137 5 : if (TALER_PROTOCOL_CURRENT < pv.current)
138 : {
139 0 : *vc |= TALER_AUDITOR_VC_NEWER;
140 0 : if (TALER_PROTOCOL_CURRENT < pv.current - pv.age)
141 0 : *vc |= TALER_AUDITOR_VC_INCOMPATIBLE;
142 : }
143 5 : if (TALER_PROTOCOL_CURRENT > pv.current)
144 : {
145 0 : *vc |= TALER_AUDITOR_VC_OLDER;
146 0 : if (TALER_PROTOCOL_CURRENT - TALER_PROTOCOL_AGE > pv.current)
147 0 : *vc |= TALER_AUDITOR_VC_INCOMPATIBLE;
148 : }
149 5 : return TALER_EC_NONE;
150 : }
151 :
152 :
153 : /**
154 : * Callback used when downloading the reply to a /config request
155 : * is complete.
156 : *
157 : * @param cls the `struct TALER_AUDITOR_GetConfigHandle`
158 : * @param response_code HTTP response code, 0 on error
159 : * @param gresp_obj parsed JSON result, NULL on error, must be a `const json_t *`
160 : */
161 : static void
162 5 : config_completed_cb (void *cls,
163 : long response_code,
164 : const void *gresp_obj)
165 : {
166 5 : struct TALER_AUDITOR_GetConfigHandle *auditor = cls;
167 5 : const json_t *resp_obj = gresp_obj;
168 5 : struct TALER_AUDITOR_ConfigResponse vr = {
169 : .hr.reply = resp_obj,
170 5 : .hr.http_status = (unsigned int) response_code
171 : };
172 :
173 5 : auditor->vr = NULL;
174 5 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
175 : "Received config from URL `%s' with status %ld.\n",
176 : auditor->vr_url,
177 : response_code);
178 5 : switch (response_code)
179 : {
180 0 : case 0:
181 0 : GNUNET_break_op (0);
182 0 : vr.hr.ec = TALER_EC_INVALID;
183 0 : break;
184 5 : case MHD_HTTP_OK:
185 5 : if (NULL == resp_obj)
186 : {
187 0 : GNUNET_break_op (0);
188 0 : vr.hr.http_status = 0;
189 0 : vr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
190 0 : break;
191 : }
192 5 : vr.hr.ec = decode_config_json (resp_obj,
193 : &vr.details.ok.vi,
194 : &vr.details.ok.compat);
195 5 : if (TALER_EC_NONE != vr.hr.ec)
196 : {
197 0 : GNUNET_break_op (0);
198 0 : vr.hr.http_status = 0;
199 0 : break;
200 : }
201 5 : break;
202 0 : case MHD_HTTP_INTERNAL_SERVER_ERROR:
203 0 : vr.hr.ec = TALER_JSON_get_error_code (resp_obj);
204 0 : vr.hr.hint = TALER_JSON_get_error_hint (resp_obj);
205 0 : break;
206 0 : default:
207 0 : vr.hr.ec = TALER_JSON_get_error_code (resp_obj);
208 0 : vr.hr.hint = TALER_JSON_get_error_hint (resp_obj);
209 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
210 : "Unexpected response code %u/%d\n",
211 : (unsigned int) response_code,
212 : (int) vr.hr.ec);
213 0 : break;
214 : }
215 5 : auditor->config_cb (auditor->config_cb_cls,
216 : &vr);
217 5 : TALER_AUDITOR_get_config_cancel (auditor);
218 5 : }
219 :
220 :
221 : struct TALER_AUDITOR_GetConfigHandle *
222 5 : TALER_AUDITOR_get_config (struct GNUNET_CURL_Context *ctx,
223 : const char *url,
224 : TALER_AUDITOR_ConfigCallback config_cb,
225 : void *config_cb_cls)
226 : {
227 : struct TALER_AUDITOR_GetConfigHandle *auditor;
228 : CURL *eh;
229 :
230 5 : auditor = GNUNET_new (struct TALER_AUDITOR_GetConfigHandle);
231 5 : auditor->config_cb = config_cb;
232 5 : auditor->config_cb_cls = config_cb_cls;
233 5 : auditor->ctx = ctx;
234 5 : auditor->vr_url = TALER_url_join (url,
235 : "config",
236 : NULL);
237 5 : if (NULL == auditor->vr_url)
238 : {
239 0 : GNUNET_break (0);
240 0 : GNUNET_free (auditor);
241 0 : return NULL;
242 : }
243 5 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
244 : "Requesting auditor config with URL `%s'.\n",
245 : auditor->vr_url);
246 5 : eh = TALER_AUDITOR_curl_easy_get_ (auditor->vr_url);
247 5 : if (NULL == eh)
248 : {
249 0 : GNUNET_break (0);
250 0 : TALER_AUDITOR_get_config_cancel (auditor);
251 0 : return NULL;
252 : }
253 5 : GNUNET_break (CURLE_OK ==
254 : curl_easy_setopt (eh,
255 : CURLOPT_TIMEOUT,
256 : (long) 300));
257 5 : auditor->vr = GNUNET_CURL_job_add (auditor->ctx,
258 : eh,
259 : &config_completed_cb,
260 : auditor);
261 5 : return auditor;
262 : }
263 :
264 :
265 : void
266 5 : TALER_AUDITOR_get_config_cancel (struct TALER_AUDITOR_GetConfigHandle *auditor)
267 : {
268 5 : if (NULL != auditor->vr)
269 : {
270 0 : GNUNET_CURL_job_cancel (auditor->vr);
271 0 : auditor->vr = NULL;
272 : }
273 5 : GNUNET_free (auditor->vr_url);
274 5 : GNUNET_free (auditor);
275 5 : }
276 :
277 :
278 : /* end of auditor_api_get_config.c */
|