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