Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2024 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it
6 : under the terms of the GNU General Public License as published by
7 : the Free Software Foundation; either version 3, or (at your
8 : 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 GNU
13 : 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_bank_admin_add_kycauth.c
21 : * @brief implementation of a bank /admin/add-kycauth command
22 : * @author Christian Grothoff
23 : * @author Marcello Stanisci
24 : */
25 : #include "taler/taler_json_lib.h"
26 : #include <gnunet/gnunet_curl_lib.h>
27 : #include "taler/taler_bank_service.h"
28 : #include "taler/taler_signatures.h"
29 : #include "taler/taler_testing_lib.h"
30 :
31 :
32 : /**
33 : * State for a KYCAUTH wire transfer CMD.
34 : */
35 : struct AdminAddKycauthState
36 : {
37 :
38 : /**
39 : * Label of any command that can trait-offer an account priv.
40 : */
41 : const char *account_ref;
42 :
43 : /**
44 : * Wire transfer amount.
45 : */
46 : struct TALER_Amount amount;
47 :
48 : /**
49 : * Base URL of the credited account.
50 : */
51 : const char *exchange_credit_url;
52 :
53 : /**
54 : * Money sender payto URL.
55 : */
56 : struct TALER_FullPayto payto_debit_account;
57 :
58 : /**
59 : * Username to use for authentication.
60 : */
61 : struct TALER_BANK_AuthenticationData auth;
62 :
63 : /**
64 : * Set (by the interpreter) to the account's private key
65 : * we used to make a wire transfer subject line with.
66 : */
67 : union TALER_AccountPrivateKeyP account_priv;
68 :
69 : /**
70 : * Account public key matching @e account_priv.
71 : */
72 : union TALER_AccountPublicKeyP account_pub;
73 :
74 : /**
75 : * Handle to the pending request at the bank.
76 : */
77 : struct TALER_BANK_AdminAddKycauthHandle *aih;
78 :
79 : /**
80 : * Interpreter state.
81 : */
82 : struct TALER_TESTING_Interpreter *is;
83 :
84 : /**
85 : * Set to the wire transfer's unique ID.
86 : */
87 : uint64_t serial_id;
88 :
89 : /**
90 : * Timestamp of the transaction (as returned from the bank).
91 : */
92 : struct GNUNET_TIME_Timestamp timestamp;
93 :
94 : /**
95 : * Expected HTTP status code.
96 : */
97 : unsigned int expected_http_status;
98 :
99 : /**
100 : * Do we have @e account_priv?
101 : */
102 : bool have_priv;
103 : };
104 :
105 :
106 : /**
107 : * This callback will process the bank response to the wire
108 : * transfer. It just checks whether the HTTP response code is
109 : * acceptable.
110 : *
111 : * @param cls closure with the interpreter state
112 : * @param air response details
113 : */
114 : static void
115 16 : confirmation_cb (void *cls,
116 : const struct TALER_BANK_AdminAddKycauthResponse *air)
117 : {
118 16 : struct AdminAddKycauthState *fts = cls;
119 16 : struct TALER_TESTING_Interpreter *is = fts->is;
120 :
121 16 : fts->aih = NULL;
122 16 : if (air->http_status != fts->expected_http_status)
123 : {
124 0 : TALER_TESTING_unexpected_status (is,
125 : air->http_status,
126 : fts->expected_http_status);
127 0 : return;
128 : }
129 16 : switch (air->http_status)
130 : {
131 16 : case MHD_HTTP_OK:
132 : fts->serial_id
133 16 : = air->details.ok.serial_id;
134 : fts->timestamp
135 16 : = air->details.ok.timestamp;
136 16 : TALER_TESTING_interpreter_next (is);
137 16 : return;
138 0 : case MHD_HTTP_UNAUTHORIZED:
139 0 : switch (fts->auth.method)
140 : {
141 0 : case TALER_BANK_AUTH_NONE:
142 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
143 : "Authentication required, but none configure.\n");
144 0 : break;
145 0 : case TALER_BANK_AUTH_BASIC:
146 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
147 : "Basic authentication (%s) failed.\n",
148 : fts->auth.details.basic.username);
149 0 : break;
150 0 : case TALER_BANK_AUTH_BEARER:
151 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
152 : "Bearer authentication (%s) failed.\n",
153 : fts->auth.details.bearer.token);
154 0 : break;
155 : }
156 0 : break;
157 0 : case MHD_HTTP_CONFLICT:
158 0 : TALER_TESTING_interpreter_next (is);
159 0 : return;
160 0 : default:
161 0 : GNUNET_break (0);
162 0 : break;
163 : }
164 0 : GNUNET_break (0);
165 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
166 : "Bank returned HTTP status %u/%d\n",
167 : air->http_status,
168 : (int) air->ec);
169 0 : TALER_TESTING_interpreter_fail (is);
170 : }
171 :
172 :
173 : /**
174 : * Run the KYC AUTH transfer CMD.
175 : *
176 : * @param cls closure.
177 : * @param cmd CMD being run.
178 : * @param is interpreter state.
179 : */
180 : static void
181 16 : admin_add_kycauth_run (void *cls,
182 : const struct TALER_TESTING_Command *cmd,
183 : struct TALER_TESTING_Interpreter *is)
184 : {
185 16 : struct AdminAddKycauthState *fts = cls;
186 :
187 : (void) cmd;
188 16 : fts->is = is;
189 : /* Use account public key as subject */
190 16 : if (NULL != fts->account_ref)
191 : {
192 : const struct TALER_TESTING_Command *ref;
193 : const union TALER_AccountPrivateKeyP *account_priv;
194 :
195 10 : ref = TALER_TESTING_interpreter_lookup_command (
196 : is,
197 : fts->account_ref);
198 10 : if (NULL == ref)
199 : {
200 0 : GNUNET_break (0);
201 0 : TALER_TESTING_interpreter_fail (is);
202 0 : return;
203 : }
204 10 : if (GNUNET_OK !=
205 10 : TALER_TESTING_get_trait_account_priv (ref,
206 : &account_priv))
207 : {
208 : const union TALER_AccountPublicKeyP *account_pub;
209 :
210 0 : if (GNUNET_OK !=
211 0 : TALER_TESTING_get_trait_account_pub (ref,
212 : &account_pub))
213 : {
214 0 : GNUNET_break (0);
215 0 : TALER_TESTING_interpreter_fail (is);
216 0 : return;
217 : }
218 0 : fts->account_pub = *account_pub;
219 : }
220 : else
221 : {
222 10 : fts->account_priv = *account_priv;
223 10 : fts->have_priv = true;
224 10 : GNUNET_CRYPTO_eddsa_key_get_public (
225 10 : &fts->account_priv.merchant_priv.eddsa_priv,
226 : &fts->account_pub.merchant_pub.eddsa_pub);
227 : }
228 : }
229 : else
230 : {
231 : /* No referenced account, no instance to take priv
232 : * from, no explicit subject given: create new key! */
233 6 : GNUNET_CRYPTO_eddsa_key_create (
234 : &fts->account_priv.merchant_priv.eddsa_priv);
235 6 : fts->have_priv = true;
236 6 : GNUNET_CRYPTO_eddsa_key_get_public (
237 6 : &fts->account_priv.merchant_priv.eddsa_priv,
238 : &fts->account_pub.merchant_pub.eddsa_pub);
239 : }
240 : fts->aih
241 16 : = TALER_BANK_admin_add_kycauth (
242 : TALER_TESTING_interpreter_get_context (is),
243 16 : &fts->auth,
244 16 : &fts->account_pub,
245 16 : &fts->amount,
246 : fts->payto_debit_account,
247 : &confirmation_cb,
248 : fts);
249 16 : if (NULL == fts->aih)
250 : {
251 0 : GNUNET_break (0);
252 0 : TALER_TESTING_interpreter_fail (is);
253 0 : return;
254 : }
255 : }
256 :
257 :
258 : /**
259 : * Free the state of a "/admin/add-kycauth" CMD, and possibly
260 : * cancel a pending operation thereof.
261 : *
262 : * @param cls closure
263 : * @param cmd current CMD being cleaned up.
264 : */
265 : static void
266 16 : admin_add_kycauth_cleanup (void *cls,
267 : const struct TALER_TESTING_Command *cmd)
268 : {
269 16 : struct AdminAddKycauthState *fts = cls;
270 :
271 16 : if (NULL != fts->aih)
272 : {
273 0 : TALER_TESTING_command_incomplete (fts->is,
274 : cmd->label);
275 0 : TALER_BANK_admin_add_kycauth_cancel (fts->aih);
276 0 : fts->aih = NULL;
277 : }
278 16 : GNUNET_free (fts);
279 16 : }
280 :
281 :
282 : /**
283 : * Offer internal data from a "/admin/add-kycauth" CMD to other
284 : * commands.
285 : *
286 : * @param cls closure.
287 : * @param[out] ret result
288 : * @param trait name of the trait.
289 : * @param index index number of the object to offer.
290 : * @return #GNUNET_OK on success.
291 : */
292 : static enum GNUNET_GenericReturnValue
293 33 : admin_add_kycauth_traits (void *cls,
294 : const void **ret,
295 : const char *trait,
296 : unsigned int index)
297 : {
298 33 : struct AdminAddKycauthState *fts = cls;
299 : static struct TALER_FullPayto void_uri = {
300 : .full_payto = (char *) "payto://void/the-exchange?receiver=name=exchange"
301 : };
302 : struct TALER_TESTING_Trait traits[] = {
303 : /* must be first! */
304 33 : TALER_TESTING_make_trait_account_priv (&fts->account_priv),
305 33 : TALER_TESTING_make_trait_bank_row (&fts->serial_id),
306 33 : TALER_TESTING_make_trait_debit_payto_uri (&fts->payto_debit_account),
307 33 : TALER_TESTING_make_trait_full_payto_uri (&fts->payto_debit_account),
308 : /* Used as a marker, content does not matter */
309 33 : TALER_TESTING_make_trait_credit_payto_uri (&void_uri),
310 33 : TALER_TESTING_make_trait_exchange_bank_account_url (
311 : fts->exchange_credit_url),
312 33 : TALER_TESTING_make_trait_amount (&fts->amount),
313 33 : TALER_TESTING_make_trait_timestamp (0,
314 33 : &fts->timestamp),
315 33 : TALER_TESTING_make_trait_account_pub (&fts->account_pub),
316 33 : TALER_TESTING_trait_end ()
317 : };
318 :
319 33 : if (MHD_HTTP_OK !=
320 33 : fts->expected_http_status)
321 0 : return GNUNET_NO; /* requests that failed generate no history */
322 :
323 33 : return TALER_TESTING_get_trait (traits + (fts->have_priv ? 0 : 1),
324 : ret,
325 : trait,
326 : index);
327 : }
328 :
329 :
330 : /**
331 : * Create internal state for "/admin/add-kycauth" CMD.
332 : *
333 : * @param amount the amount to transfer.
334 : * @param payto_debit_account which account sends money
335 : * @param auth authentication data
336 : * @param account_ref reference to command with account
337 : * private key to use; NULL to create a fresh key pair
338 : * @return the internal state
339 : */
340 : static struct AdminAddKycauthState *
341 16 : make_fts (const char *amount,
342 : const struct TALER_BANK_AuthenticationData *auth,
343 : const struct TALER_FullPayto payto_debit_account,
344 : const char *account_ref)
345 : {
346 : struct AdminAddKycauthState *fts;
347 :
348 16 : fts = GNUNET_new (struct AdminAddKycauthState);
349 16 : fts->exchange_credit_url = auth->wire_gateway_url;
350 16 : fts->payto_debit_account = payto_debit_account;
351 16 : fts->account_ref = account_ref;
352 16 : fts->auth = *auth;
353 16 : fts->expected_http_status = MHD_HTTP_OK;
354 16 : if (GNUNET_OK !=
355 16 : TALER_string_to_amount (amount,
356 : &fts->amount))
357 : {
358 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
359 : "Failed to parse amount `%s'\n",
360 : amount);
361 0 : GNUNET_assert (0);
362 : }
363 16 : return fts;
364 : }
365 :
366 :
367 : struct TALER_TESTING_Command
368 16 : TALER_TESTING_cmd_admin_add_kycauth (
369 : const char *label,
370 : const char *amount,
371 : const struct TALER_BANK_AuthenticationData *auth,
372 : const struct TALER_FullPayto payto_debit_account,
373 : const char *account_ref)
374 : {
375 32 : struct TALER_TESTING_Command cmd = {
376 16 : .cls = make_fts (amount,
377 : auth,
378 : payto_debit_account,
379 : account_ref),
380 : .label = label,
381 : .run = &admin_add_kycauth_run,
382 : .cleanup = &admin_add_kycauth_cleanup,
383 : .traits = &admin_add_kycauth_traits
384 : };
385 :
386 16 : return cmd;
387 : }
388 :
389 :
390 : /* end of testing_api_cmd_bank_admin_add_kycauth.c */
|