Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2021-2026 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 : /**
21 : * @file testing/testing_api_cmd_kyc_proof.c
22 : * @brief Implement the testing CMDs for the /kyc-proof/ operation.
23 : * @author Christian Grothoff
24 : */
25 : #include "taler/taler_json_lib.h"
26 : #include <gnunet/gnunet_curl_lib.h>
27 :
28 : /**
29 : * State for a "track transaction" CMD.
30 : */
31 : struct KycProofGetState;
32 :
33 : #define TALER_EXCHANGE_GET_KYC_PROOF_RESULT_CLOSURE \
34 : struct KycProofGetState
35 : #include "taler/exchange/get-kyc-proof-PROVIDER_NAME.h"
36 : #include "taler/taler_testing_lib.h"
37 :
38 : /**
39 : * State for a "track transaction" CMD.
40 : */
41 : struct KycProofGetState
42 : {
43 :
44 : /**
45 : * Command to get the OAuth2 state from: a KYC start command
46 : * offering the KYC URL, or any command offering a payment target,
47 : * whose bare hash is then used as the state.
48 : */
49 : const char *state_reference;
50 :
51 : /**
52 : * Code to pass.
53 : */
54 : const char *code;
55 :
56 : /**
57 : * Logic section name to pass to `/kyc-proof/` handler.
58 : */
59 : const char *logic;
60 :
61 : /**
62 : * Expected HTTP response code.
63 : */
64 : unsigned int expected_response_code;
65 :
66 : /**
67 : * Set to the KYC REDIRECT *if* the exchange replied with
68 : * success (#MHD_HTTP_OK).
69 : */
70 : char *redirect_url;
71 :
72 : /**
73 : * Additional URL arguments (e.g. "&code=..."), kept alive
74 : * for the lifetime of the request.
75 : */
76 : char *uargs;
77 :
78 : /**
79 : * Handle to the "track transaction" pending operation.
80 : */
81 : struct TALER_EXCHANGE_GetKycProofHandle *kph;
82 :
83 : /**
84 : * Interpreter state.
85 : */
86 : struct TALER_TESTING_Interpreter *is;
87 : };
88 :
89 :
90 : /**
91 : * Handle response to the command.
92 : *
93 : * @param kcg our state
94 : * @param kpr KYC proof response details
95 : */
96 : static void
97 12 : proof_kyc_cb (
98 : struct KycProofGetState *kcg,
99 : const struct TALER_EXCHANGE_GetKycProofResponse *kpr)
100 : {
101 12 : struct TALER_TESTING_Interpreter *is = kcg->is;
102 :
103 12 : kcg->kph = NULL;
104 12 : if (kcg->expected_response_code != kpr->hr.http_status)
105 : {
106 0 : TALER_TESTING_unexpected_status (is,
107 : kpr->hr.http_status,
108 : kcg->expected_response_code);
109 0 : return;
110 : }
111 12 : switch (kpr->hr.http_status)
112 : {
113 9 : case MHD_HTTP_SEE_OTHER:
114 9 : kcg->redirect_url = GNUNET_strdup (kpr->details.see_other.redirect_url);
115 9 : break;
116 2 : case MHD_HTTP_FORBIDDEN:
117 2 : break;
118 1 : case MHD_HTTP_BAD_GATEWAY:
119 1 : break;
120 0 : default:
121 0 : GNUNET_break (0);
122 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
123 : "Unexpected response code %u to /kyc-proof\n",
124 : kpr->hr.http_status);
125 0 : break;
126 : }
127 12 : TALER_TESTING_interpreter_next (kcg->is);
128 : }
129 :
130 :
131 : /**
132 : * Extract the OAuth2 state from the authorization URL
133 : * the exchange returned to start a KYC process.
134 : *
135 : * @param kyc_url authorization URL to parse
136 : * @return the state, NULL if @a kyc_url has none
137 : */
138 : static char *
139 11 : get_state (const char *kyc_url)
140 : {
141 : const char *q;
142 :
143 11 : q = strchr (kyc_url,
144 : '?');
145 44 : while (NULL != q)
146 : {
147 44 : q++;
148 44 : if (0 == strncmp (q,
149 : "state=",
150 : strlen ("state=")))
151 : {
152 11 : q += strlen ("state=");
153 11 : return GNUNET_strndup (q,
154 : strcspn (q,
155 : "&#"));
156 : }
157 33 : q = strchr (q,
158 : '&');
159 : }
160 0 : return NULL;
161 : }
162 :
163 :
164 : /**
165 : * Run the command.
166 : *
167 : * @param cls closure.
168 : * @param cmd the command to execute.
169 : * @param is the interpreter state.
170 : */
171 : static void
172 12 : proof_kyc_run (void *cls,
173 : const struct TALER_TESTING_Command *cmd,
174 : struct TALER_TESTING_Interpreter *is)
175 : {
176 12 : struct KycProofGetState *kps = cls;
177 : const struct TALER_TESTING_Command *res_cmd;
178 : const char *kyc_url;
179 : char *state;
180 : const char *exchange_url;
181 :
182 : (void) cmd;
183 12 : kps->is = is;
184 12 : exchange_url = TALER_TESTING_get_exchange_url (is);
185 12 : if (NULL == exchange_url)
186 : {
187 0 : GNUNET_break (0);
188 0 : return;
189 : }
190 12 : res_cmd = TALER_TESTING_interpreter_lookup_command (
191 : kps->is,
192 : kps->state_reference);
193 12 : if (NULL == res_cmd)
194 : {
195 0 : GNUNET_break (0);
196 0 : TALER_TESTING_interpreter_fail (kps->is);
197 0 : return;
198 : }
199 12 : if (GNUNET_OK ==
200 12 : TALER_TESTING_get_trait_kyc_url (res_cmd,
201 : &kyc_url))
202 : {
203 : /* Use the state the exchange issued, as the provider would. */
204 11 : state = get_state (kyc_url);
205 11 : if (NULL == state)
206 : {
207 0 : GNUNET_break (0);
208 0 : TALER_TESTING_interpreter_fail (kps->is);
209 0 : return;
210 : }
211 : }
212 : else
213 : {
214 : const struct TALER_NormalizedPaytoHashP *h_payto;
215 :
216 : /* Only know the account, like anyone who did not see the
217 : authorization request. */
218 1 : if (GNUNET_OK !=
219 1 : TALER_TESTING_get_trait_h_normalized_payto (res_cmd,
220 : &h_payto))
221 : {
222 0 : GNUNET_break (0);
223 0 : TALER_TESTING_interpreter_fail (kps->is);
224 0 : return;
225 : }
226 1 : state = GNUNET_STRINGS_data_to_string_alloc (h_payto,
227 : sizeof (*h_payto));
228 : }
229 12 : if (NULL != kps->code)
230 12 : GNUNET_asprintf (&kps->uargs,
231 : "&code=%s",
232 : kps->code);
233 12 : kps->kph = TALER_EXCHANGE_get_kyc_proof_create (
234 : TALER_TESTING_interpreter_get_context (is),
235 : exchange_url,
236 : state,
237 : kps->logic);
238 12 : GNUNET_free (state);
239 12 : GNUNET_assert (NULL != kps->kph);
240 12 : if (NULL != kps->uargs)
241 12 : TALER_EXCHANGE_get_kyc_proof_set_options (
242 : kps->kph,
243 : TALER_EXCHANGE_get_kyc_proof_option_args (kps->uargs));
244 : {
245 : enum TALER_ErrorCode ec;
246 :
247 12 : ec = TALER_EXCHANGE_get_kyc_proof_start (kps->kph,
248 : &proof_kyc_cb,
249 : kps);
250 12 : if (TALER_EC_NONE != ec)
251 : {
252 0 : GNUNET_break (0);
253 0 : kps->kph = NULL;
254 0 : TALER_TESTING_interpreter_fail (kps->is);
255 0 : return;
256 : }
257 : }
258 : }
259 :
260 :
261 : /**
262 : * Cleanup the state from a "kyc proof" CMD, and possibly
263 : * cancel a operation thereof.
264 : *
265 : * @param cls closure.
266 : * @param cmd the command which is being cleaned up.
267 : */
268 : static void
269 12 : proof_kyc_cleanup (void *cls,
270 : const struct TALER_TESTING_Command *cmd)
271 : {
272 12 : struct KycProofGetState *kps = cls;
273 :
274 12 : if (NULL != kps->kph)
275 : {
276 0 : TALER_TESTING_command_incomplete (kps->is,
277 : cmd->label);
278 0 : TALER_EXCHANGE_get_kyc_proof_cancel (kps->kph);
279 0 : kps->kph = NULL;
280 : }
281 12 : GNUNET_free (kps->redirect_url);
282 12 : GNUNET_free (kps->uargs);
283 12 : GNUNET_free (kps);
284 12 : }
285 :
286 :
287 : /**
288 : * Offer internal data from a "proof KYC" CMD.
289 : *
290 : * @param cls closure.
291 : * @param[out] ret result (could be anything).
292 : * @param trait name of the trait.
293 : * @param index index number of the object to offer.
294 : * @return #GNUNET_OK on success.
295 : */
296 : static enum GNUNET_GenericReturnValue
297 31 : proof_kyc_traits (void *cls,
298 : const void **ret,
299 : const char *trait,
300 : unsigned int index)
301 : {
302 31 : struct KycProofGetState *kps = cls;
303 : struct TALER_TESTING_Trait traits[] = {
304 31 : TALER_TESTING_make_trait_web_url (kps->redirect_url),
305 31 : TALER_TESTING_trait_end ()
306 : };
307 :
308 31 : return TALER_TESTING_get_trait (traits,
309 : ret,
310 : trait,
311 : index);
312 : }
313 :
314 :
315 : struct TALER_TESTING_Command
316 12 : TALER_TESTING_cmd_proof_kyc_oauth2 (
317 : const char *label,
318 : const char *state_reference,
319 : const char *logic_section,
320 : const char *code,
321 : unsigned int expected_response_code)
322 : {
323 : struct KycProofGetState *kps;
324 :
325 12 : kps = GNUNET_new (struct KycProofGetState);
326 12 : kps->code = code;
327 12 : kps->logic = logic_section;
328 12 : kps->state_reference = state_reference;
329 12 : kps->expected_response_code = expected_response_code;
330 : {
331 12 : struct TALER_TESTING_Command cmd = {
332 : .cls = kps,
333 : .label = label,
334 : .run = &proof_kyc_run,
335 : .cleanup = &proof_kyc_cleanup,
336 : .traits = &proof_kyc_traits
337 : };
338 :
339 12 : return cmd;
340 : }
341 : }
342 :
343 :
344 : /* end of testing_api_cmd_kyc_proof.c */
|