Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2022 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU General Public License as
7 : published by the Free Software Foundation; either version 3, or
8 : (at your option) any later version.
9 :
10 : TALER is distributed in the hope that it will be useful, but
11 : WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public
16 : License along with TALER; see the file COPYING. If not, see
17 : <http://www.gnu.org/licenses/>
18 : */
19 : /**
20 : * @file testing/testing_api_cmd_reserve_attest.c
21 : * @brief Implement the /reserve/$RID/attest test command.
22 : * @author Christian Grothoff
23 : */
24 : #include "taler/taler_json_lib.h"
25 : #include <gnunet/gnunet_curl_lib.h>
26 : struct AttestState;
27 : #define TALER_EXCHANGE_POST_RESERVES_ATTEST_RESULT_CLOSURE struct AttestState
28 : #include "taler/exchange/post-reserves-attest-RESERVE_PUB.h"
29 : #include "taler/taler_testing_lib.h"
30 :
31 : /**
32 : * State for a "attest" CMD.
33 : */
34 : struct AttestState
35 : {
36 : /**
37 : * Label to the command which created the reserve to check,
38 : * needed to resort the reserve key.
39 : */
40 : const char *reserve_reference;
41 :
42 : /**
43 : * Handle to the "reserve attest" operation.
44 : */
45 : struct TALER_EXCHANGE_PostReservesAttestHandle *rsh;
46 :
47 : /**
48 : * Private key of the reserve being analyzed.
49 : */
50 : const struct TALER_ReservePrivateKeyP *reserve_priv;
51 :
52 : /**
53 : * Public key of the reserve being analyzed.
54 : */
55 : struct TALER_ReservePublicKeyP reserve_pub;
56 :
57 : /**
58 : * Array of attributes to request, of length @e attrs_len.
59 : */
60 : const char **attrs;
61 :
62 : /**
63 : * Length of the @e attrs array.
64 : */
65 : unsigned int attrs_len;
66 :
67 : /**
68 : * Expected HTTP response code.
69 : */
70 : unsigned int expected_response_code;
71 :
72 : /**
73 : * Interpreter state.
74 : */
75 : struct TALER_TESTING_Interpreter *is;
76 :
77 : /* FIXME: expose fields below as traits... */
78 :
79 : /**
80 : * Attested attributes returned by the exchange.
81 : */
82 : json_t *attributes;
83 :
84 : /**
85 : * Expiration time of the attested attributes.
86 : */
87 : struct GNUNET_TIME_Timestamp expiration_time;
88 :
89 : /**
90 : * Signature by the exchange affirming the attributes.
91 : */
92 : struct TALER_ExchangeSignatureP exchange_sig;
93 :
94 : /**
95 : * Online signing key used by the exchange.
96 : */
97 : struct TALER_ExchangePublicKeyP exchange_pub;
98 : };
99 :
100 :
101 : /**
102 : * Check that the reserve balance and HTTP response code are
103 : * both acceptable.
104 : *
105 : * @param ss closure.
106 : * @param rs HTTP response details
107 : */
108 : static void
109 1 : reserve_attest_cb (
110 : struct AttestState *ss,
111 : const struct TALER_EXCHANGE_PostReservesAttestResponse *rs)
112 : {
113 1 : struct TALER_TESTING_Interpreter *is = ss->is;
114 :
115 1 : ss->rsh = NULL;
116 1 : if (ss->expected_response_code != rs->hr.http_status)
117 : {
118 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
119 : "Unexpected HTTP response code: %d in %s:%u\n",
120 : rs->hr.http_status,
121 : __FILE__,
122 : __LINE__);
123 0 : json_dumpf (rs->hr.reply,
124 : stderr,
125 : JSON_INDENT (2));
126 0 : TALER_TESTING_interpreter_fail (ss->is);
127 0 : return;
128 : }
129 1 : if (MHD_HTTP_OK != rs->hr.http_status)
130 : {
131 0 : TALER_TESTING_interpreter_next (is);
132 0 : return;
133 : }
134 1 : ss->attributes = json_incref ((json_t*) rs->details.ok.attributes);
135 1 : ss->expiration_time = rs->details.ok.expiration_time;
136 1 : ss->exchange_pub = rs->details.ok.exchange_pub;
137 1 : ss->exchange_sig = rs->details.ok.exchange_sig;
138 1 : TALER_TESTING_interpreter_next (is);
139 : }
140 :
141 :
142 : /**
143 : * Run the command.
144 : *
145 : * @param cls closure.
146 : * @param cmd the command being executed.
147 : * @param is the interpreter state.
148 : */
149 : static void
150 1 : attest_run (void *cls,
151 : const struct TALER_TESTING_Command *cmd,
152 : struct TALER_TESTING_Interpreter *is)
153 : {
154 1 : struct AttestState *ss = cls;
155 : const struct TALER_TESTING_Command *create_reserve;
156 : const char *exchange_url;
157 :
158 1 : ss->is = is;
159 1 : exchange_url = TALER_TESTING_get_exchange_url (is);
160 1 : if (NULL == exchange_url)
161 : {
162 0 : GNUNET_break (0);
163 0 : return;
164 : }
165 : create_reserve
166 1 : = TALER_TESTING_interpreter_lookup_command (is,
167 : ss->reserve_reference);
168 :
169 1 : if (NULL == create_reserve)
170 : {
171 0 : GNUNET_break (0);
172 0 : TALER_TESTING_interpreter_fail (is);
173 0 : return;
174 : }
175 1 : if (GNUNET_OK !=
176 1 : TALER_TESTING_get_trait_reserve_priv (create_reserve,
177 : &ss->reserve_priv))
178 : {
179 0 : GNUNET_break (0);
180 0 : TALER_LOG_ERROR ("Failed to find reserve_priv for attest query\n");
181 0 : TALER_TESTING_interpreter_fail (is);
182 0 : return;
183 : }
184 1 : GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv,
185 : &ss->reserve_pub.eddsa_pub);
186 1 : ss->rsh = TALER_EXCHANGE_post_reserves_attest_create (
187 : TALER_TESTING_interpreter_get_context (is),
188 : exchange_url,
189 : TALER_TESTING_get_keys (is),
190 : ss->reserve_priv,
191 : ss->attrs_len,
192 : ss->attrs);
193 1 : if (NULL == ss->rsh)
194 : {
195 0 : GNUNET_break (0);
196 0 : TALER_TESTING_interpreter_fail (is);
197 0 : return;
198 : }
199 : {
200 : enum TALER_ErrorCode ec;
201 :
202 1 : ec = TALER_EXCHANGE_post_reserves_attest_start (ss->rsh,
203 : &reserve_attest_cb,
204 : ss);
205 1 : if (TALER_EC_NONE != ec)
206 : {
207 0 : GNUNET_break (0);
208 0 : ss->rsh = NULL;
209 0 : TALER_TESTING_interpreter_fail (is);
210 0 : return;
211 : }
212 : }
213 : }
214 :
215 :
216 : /**
217 : * Cleanup the state from a "reserve attest" CMD, and possibly
218 : * cancel a pending operation thereof.
219 : *
220 : * @param cls closure.
221 : * @param cmd the command which is being cleaned up.
222 : */
223 : static void
224 1 : attest_cleanup (void *cls,
225 : const struct TALER_TESTING_Command *cmd)
226 : {
227 1 : struct AttestState *ss = cls;
228 :
229 1 : if (NULL != ss->rsh)
230 : {
231 0 : TALER_TESTING_command_incomplete (ss->is,
232 : cmd->label);
233 0 : TALER_EXCHANGE_post_reserves_attest_cancel (ss->rsh);
234 0 : ss->rsh = NULL;
235 : }
236 1 : json_decref (ss->attributes);
237 1 : GNUNET_free (ss->attrs);
238 1 : GNUNET_free (ss);
239 1 : }
240 :
241 :
242 : struct TALER_TESTING_Command
243 1 : TALER_TESTING_cmd_reserve_attest (const char *label,
244 : const char *reserve_reference,
245 : unsigned int expected_response_code,
246 : ...)
247 : {
248 : struct AttestState *ss;
249 : unsigned int num_args;
250 : const char *ea;
251 : va_list ap;
252 :
253 1 : num_args = 0;
254 1 : va_start (ap, expected_response_code);
255 2 : while (NULL != va_arg (ap, const char *))
256 1 : num_args++;
257 1 : va_end (ap);
258 :
259 1 : GNUNET_assert (NULL != reserve_reference);
260 1 : ss = GNUNET_new (struct AttestState);
261 1 : ss->reserve_reference = reserve_reference;
262 1 : ss->expected_response_code = expected_response_code;
263 1 : ss->attrs_len = num_args;
264 1 : ss->attrs = GNUNET_new_array (num_args,
265 : const char *);
266 1 : num_args = 0;
267 1 : va_start (ap, expected_response_code);
268 2 : while (NULL != (ea = va_arg (ap, const char *)))
269 1 : ss->attrs[num_args++] = ea;
270 1 : va_end (ap);
271 :
272 : {
273 1 : struct TALER_TESTING_Command cmd = {
274 : .cls = ss,
275 : .label = label,
276 : .run = &attest_run,
277 : .cleanup = &attest_cleanup
278 : };
279 :
280 1 : return cmd;
281 : }
282 : }
|