Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2024 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_close.c
21 : * @brief Implement the /reserve/$RID/close test command.
22 : * @author Christian Grothoff
23 : */
24 : #include "taler/taler_json_lib.h"
25 : #include <gnunet/gnunet_curl_lib.h>
26 : #include "taler/taler_testing_lib.h"
27 :
28 :
29 : /**
30 : * State for a "close" CMD.
31 : */
32 : struct CloseState
33 : {
34 : /**
35 : * Label to the command which created the reserve to check,
36 : * needed to resort the reserve key.
37 : */
38 : const char *reserve_reference;
39 :
40 : /**
41 : * Handle to the "reserve close" operation.
42 : */
43 : struct TALER_EXCHANGE_PostReservesCloseHandle *rsh;
44 :
45 : /**
46 : * payto://-URI where to wire the funds.
47 : */
48 : struct TALER_FullPayto target_account;
49 :
50 : /**
51 : * Private key of the reserve being analyzed.
52 : */
53 : const struct TALER_ReservePrivateKeyP *reserve_priv;
54 :
55 : /**
56 : * Public key of the reserve being analyzed.
57 : */
58 : struct TALER_ReservePublicKeyP reserve_pub;
59 :
60 : /**
61 : * Expected HTTP response code.
62 : */
63 : unsigned int expected_response_code;
64 :
65 : /**
66 : * Interpreter state.
67 : */
68 : struct TALER_TESTING_Interpreter *is;
69 :
70 : /**
71 : * Set to the KYC requirement payto hash *if* the exchange replied with a
72 : * request for KYC.
73 : */
74 : struct TALER_NormalizedPaytoHashP h_payto;
75 :
76 : /**
77 : * Set to the KYC requirement row *if* the exchange replied with
78 : * a request for KYC.
79 : */
80 : uint64_t requirement_row;
81 : };
82 :
83 :
84 : /**
85 : * Check that the reserve balance and HTTP response code are
86 : * both acceptable.
87 : *
88 : * @param cls closure.
89 : * @param rs HTTP response details
90 : */
91 : static void
92 4 : reserve_close_cb (void *cls,
93 : const struct TALER_EXCHANGE_PostReservesCloseResponse *rs)
94 : {
95 4 : struct CloseState *ss = cls;
96 4 : struct TALER_TESTING_Interpreter *is = ss->is;
97 :
98 4 : ss->rsh = NULL;
99 4 : if (ss->expected_response_code != rs->hr.http_status)
100 : {
101 0 : TALER_TESTING_unexpected_status (ss->is,
102 : rs->hr.http_status,
103 : ss->expected_response_code);
104 0 : json_dumpf (rs->hr.reply,
105 : stderr,
106 : JSON_INDENT (2));
107 0 : return;
108 : }
109 4 : switch (rs->hr.http_status)
110 : {
111 2 : case MHD_HTTP_OK:
112 2 : break;
113 2 : case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
114 : /* nothing to check */
115 : ss->requirement_row
116 2 : = rs->details.unavailable_for_legal_reasons.requirement_row;
117 : ss->h_payto
118 2 : = rs->details.unavailable_for_legal_reasons.h_payto;
119 2 : break;
120 0 : default:
121 0 : break;
122 : }
123 4 : TALER_TESTING_interpreter_next (is);
124 : }
125 :
126 :
127 : /**
128 : * Run the command.
129 : *
130 : * @param cls closure.
131 : * @param cmd the command being executed.
132 : * @param is the interpreter state.
133 : */
134 : static void
135 4 : close_run (void *cls,
136 : const struct TALER_TESTING_Command *cmd,
137 : struct TALER_TESTING_Interpreter *is)
138 : {
139 4 : struct CloseState *ss = cls;
140 : const struct TALER_TESTING_Command *create_reserve;
141 :
142 4 : ss->is = is;
143 : create_reserve
144 4 : = TALER_TESTING_interpreter_lookup_command (is,
145 : ss->reserve_reference);
146 :
147 4 : if (NULL == create_reserve)
148 : {
149 0 : GNUNET_break (0);
150 0 : TALER_TESTING_interpreter_fail (is);
151 0 : return;
152 : }
153 4 : if (GNUNET_OK !=
154 4 : TALER_TESTING_get_trait_reserve_priv (create_reserve,
155 : &ss->reserve_priv))
156 : {
157 0 : GNUNET_break (0);
158 0 : TALER_LOG_ERROR ("Failed to find reserve_priv for close query\n");
159 0 : TALER_TESTING_interpreter_fail (is);
160 0 : return;
161 : }
162 4 : GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv,
163 : &ss->reserve_pub.eddsa_pub);
164 4 : ss->rsh = TALER_EXCHANGE_post_reserves_close_create (
165 : TALER_TESTING_interpreter_get_context (is),
166 : TALER_TESTING_get_exchange_url (is),
167 : ss->reserve_priv);
168 4 : if (NULL == ss->rsh)
169 : {
170 0 : GNUNET_break (0);
171 0 : TALER_TESTING_interpreter_fail (is);
172 0 : return;
173 : }
174 4 : if (NULL != ss->target_account.full_payto)
175 : {
176 4 : TALER_EXCHANGE_post_reserves_close_set_options (
177 : ss->rsh,
178 : TALER_EXCHANGE_post_reserves_close_option_payto_uri (
179 : ss->target_account));
180 : }
181 : {
182 : enum TALER_ErrorCode ec;
183 :
184 4 : ec = TALER_EXCHANGE_post_reserves_close_start (ss->rsh,
185 : &reserve_close_cb,
186 : ss);
187 4 : if (TALER_EC_NONE != ec)
188 : {
189 0 : GNUNET_break (0);
190 0 : ss->rsh = NULL;
191 0 : TALER_TESTING_interpreter_fail (is);
192 0 : return;
193 : }
194 : }
195 : }
196 :
197 :
198 : /**
199 : * Cleanup the state from a "reserve close" CMD, and possibly
200 : * cancel a pending operation thereof.
201 : *
202 : * @param cls closure.
203 : * @param cmd the command which is being cleaned up.
204 : */
205 : static void
206 4 : close_cleanup (void *cls,
207 : const struct TALER_TESTING_Command *cmd)
208 : {
209 4 : struct CloseState *ss = cls;
210 :
211 4 : if (NULL != ss->rsh)
212 : {
213 0 : TALER_TESTING_command_incomplete (ss->is,
214 : cmd->label);
215 0 : TALER_EXCHANGE_post_reserves_close_cancel (ss->rsh);
216 0 : ss->rsh = NULL;
217 : }
218 4 : GNUNET_free (ss);
219 4 : }
220 :
221 :
222 : /**
223 : * Offer internal data to a "close" CMD state to other
224 : * commands.
225 : *
226 : * @param cls closure
227 : * @param[out] ret result (could be anything)
228 : * @param trait name of the trait
229 : * @param index index number of the object to offer.
230 : * @return #GNUNET_OK on success
231 : */
232 : static enum GNUNET_GenericReturnValue
233 6 : close_traits (void *cls,
234 : const void **ret,
235 : const char *trait,
236 : unsigned int index)
237 : {
238 6 : struct CloseState *cs = cls;
239 : struct TALER_TESTING_Trait traits[] = {
240 6 : TALER_TESTING_make_trait_legi_requirement_row (
241 6 : &cs->requirement_row),
242 6 : TALER_TESTING_make_trait_h_normalized_payto (
243 6 : &cs->h_payto),
244 6 : TALER_TESTING_trait_end ()
245 : };
246 :
247 6 : if (cs->expected_response_code != MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS)
248 0 : return GNUNET_NO;
249 6 : return TALER_TESTING_get_trait (traits,
250 : ret,
251 : trait,
252 : index);
253 : }
254 :
255 :
256 : struct TALER_TESTING_Command
257 4 : TALER_TESTING_cmd_reserve_close (const char *label,
258 : const char *reserve_reference,
259 : struct TALER_FullPayto target_account,
260 : unsigned int expected_response_code)
261 : {
262 : struct CloseState *ss;
263 :
264 4 : GNUNET_assert (NULL != reserve_reference);
265 4 : ss = GNUNET_new (struct CloseState);
266 4 : ss->reserve_reference = reserve_reference;
267 4 : ss->target_account = target_account;
268 4 : ss->expected_response_code = expected_response_code;
269 : {
270 4 : struct TALER_TESTING_Command cmd = {
271 : .cls = ss,
272 : .label = label,
273 : .run = &close_run,
274 : .cleanup = &close_cleanup,
275 : .traits = &close_traits
276 : };
277 :
278 4 : return cmd;
279 : }
280 : }
|