Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2015-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/exchange_api_common.c
19 : * @brief common functions for the exchange API
20 : * @author Christian Grothoff
21 : */
22 : #include "taler/taler_json_lib.h"
23 : #include <gnunet/gnunet_curl_lib.h>
24 : #include "exchange_api_common.h"
25 : #include "exchange_api_handle.h"
26 : #include "taler/taler_signatures.h"
27 :
28 :
29 : const struct TALER_EXCHANGE_SigningPublicKey *
30 2 : TALER_EXCHANGE_get_signing_key_info (
31 : const struct TALER_EXCHANGE_Keys *keys,
32 : const struct TALER_ExchangePublicKeyP *exchange_pub)
33 : {
34 2 : for (unsigned int i = 0; i<keys->num_sign_keys; i++)
35 : {
36 2 : const struct TALER_EXCHANGE_SigningPublicKey *spk
37 2 : = &keys->sign_keys[i];
38 :
39 2 : if (0 == GNUNET_memcmp (exchange_pub,
40 : &spk->key))
41 2 : return spk;
42 : }
43 0 : return NULL;
44 : }
45 :
46 :
47 : enum GNUNET_GenericReturnValue
48 0 : TALER_EXCHANGE_check_purse_create_conflict_ (
49 : const struct TALER_PurseContractSignatureP *cpurse_sig,
50 : const struct TALER_PurseContractPublicKeyP *purse_pub,
51 : const json_t *proof)
52 : {
53 : struct TALER_Amount amount;
54 : uint32_t min_age;
55 : struct GNUNET_TIME_Timestamp purse_expiration;
56 : struct TALER_PurseContractSignatureP purse_sig;
57 : struct TALER_PrivateContractHashP h_contract_terms;
58 : struct TALER_PurseMergePublicKeyP merge_pub;
59 : struct GNUNET_JSON_Specification spec[] = {
60 0 : TALER_JSON_spec_amount_any ("amount",
61 : &amount),
62 0 : GNUNET_JSON_spec_uint32 ("min_age",
63 : &min_age),
64 0 : GNUNET_JSON_spec_timestamp ("purse_expiration",
65 : &purse_expiration),
66 0 : GNUNET_JSON_spec_fixed_auto ("purse_sig",
67 : &purse_sig),
68 0 : GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
69 : &h_contract_terms),
70 0 : GNUNET_JSON_spec_fixed_auto ("merge_pub",
71 : &merge_pub),
72 0 : GNUNET_JSON_spec_end ()
73 : };
74 :
75 0 : if (GNUNET_OK !=
76 0 : GNUNET_JSON_parse (proof,
77 : spec,
78 : NULL, NULL))
79 : {
80 0 : GNUNET_break_op (0);
81 0 : return GNUNET_SYSERR;
82 : }
83 0 : if (GNUNET_OK !=
84 0 : TALER_wallet_purse_create_verify (purse_expiration,
85 : &h_contract_terms,
86 : &merge_pub,
87 : min_age,
88 : &amount,
89 : purse_pub,
90 : &purse_sig))
91 : {
92 0 : GNUNET_break_op (0);
93 0 : return GNUNET_SYSERR;
94 : }
95 0 : if (0 ==
96 0 : GNUNET_memcmp (&purse_sig,
97 : cpurse_sig))
98 : {
99 : /* Must be the SAME data, not a conflict! */
100 0 : GNUNET_break_op (0);
101 0 : return GNUNET_SYSERR;
102 : }
103 0 : return GNUNET_OK;
104 : }
105 :
106 :
107 : enum GNUNET_GenericReturnValue
108 2 : TALER_EXCHANGE_check_purse_merge_conflict_ (
109 : const struct TALER_PurseMergeSignatureP *cmerge_sig,
110 : const struct TALER_PurseMergePublicKeyP *merge_pub,
111 : const struct TALER_PurseContractPublicKeyP *purse_pub,
112 : const char *exchange_url,
113 : const json_t *proof)
114 : {
115 : struct TALER_PurseMergeSignatureP merge_sig;
116 : struct GNUNET_TIME_Timestamp merge_timestamp;
117 2 : const char *partner_url = NULL;
118 : struct TALER_ReservePublicKeyP reserve_pub;
119 : struct GNUNET_JSON_Specification spec[] = {
120 2 : GNUNET_JSON_spec_mark_optional (
121 : TALER_JSON_spec_web_url ("partner_url",
122 : &partner_url),
123 : NULL),
124 2 : GNUNET_JSON_spec_timestamp ("merge_timestamp",
125 : &merge_timestamp),
126 2 : GNUNET_JSON_spec_fixed_auto ("merge_sig",
127 : &merge_sig),
128 2 : GNUNET_JSON_spec_fixed_auto ("reserve_pub",
129 : &reserve_pub),
130 2 : GNUNET_JSON_spec_end ()
131 : };
132 : struct TALER_NormalizedPayto payto_uri;
133 :
134 2 : if (GNUNET_OK !=
135 2 : GNUNET_JSON_parse (proof,
136 : spec,
137 : NULL, NULL))
138 : {
139 0 : GNUNET_break_op (0);
140 0 : return GNUNET_SYSERR;
141 : }
142 2 : if (NULL == partner_url)
143 2 : partner_url = exchange_url;
144 2 : payto_uri = TALER_reserve_make_payto (partner_url,
145 : &reserve_pub);
146 2 : if (GNUNET_OK !=
147 2 : TALER_wallet_purse_merge_verify (
148 : payto_uri,
149 : merge_timestamp,
150 : purse_pub,
151 : merge_pub,
152 : &merge_sig))
153 : {
154 0 : GNUNET_break_op (0);
155 0 : GNUNET_free (payto_uri.normalized_payto);
156 0 : return GNUNET_SYSERR;
157 : }
158 2 : GNUNET_free (payto_uri.normalized_payto);
159 2 : if (0 ==
160 2 : GNUNET_memcmp (&merge_sig,
161 : cmerge_sig))
162 : {
163 : /* Must be the SAME data, not a conflict! */
164 0 : GNUNET_break_op (0);
165 0 : return GNUNET_SYSERR;
166 : }
167 2 : return GNUNET_OK;
168 : }
169 :
170 :
171 : enum GNUNET_GenericReturnValue
172 0 : TALER_EXCHANGE_check_purse_coin_conflict_ (
173 : const struct TALER_PurseContractPublicKeyP *purse_pub,
174 : const char *exchange_url,
175 : const json_t *proof,
176 : struct TALER_DenominationHashP *h_denom_pub,
177 : struct TALER_AgeCommitmentHashP *phac,
178 : struct TALER_CoinSpendPublicKeyP *coin_pub,
179 : struct TALER_CoinSpendSignatureP *coin_sig)
180 : {
181 0 : const char *partner_url = NULL;
182 : struct TALER_Amount amount;
183 : struct GNUNET_JSON_Specification spec[] = {
184 0 : GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
185 : h_denom_pub),
186 0 : GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
187 : phac),
188 0 : GNUNET_JSON_spec_fixed_auto ("coin_sig",
189 : coin_sig),
190 0 : GNUNET_JSON_spec_fixed_auto ("coin_pub",
191 : coin_pub),
192 0 : GNUNET_JSON_spec_mark_optional (
193 : TALER_JSON_spec_web_url ("partner_url",
194 : &partner_url),
195 : NULL),
196 0 : TALER_JSON_spec_amount_any ("amount",
197 : &amount),
198 0 : GNUNET_JSON_spec_end ()
199 : };
200 :
201 0 : if (GNUNET_OK !=
202 0 : GNUNET_JSON_parse (proof,
203 : spec,
204 : NULL, NULL))
205 : {
206 0 : GNUNET_break_op (0);
207 0 : return GNUNET_SYSERR;
208 : }
209 0 : if (NULL == partner_url)
210 0 : partner_url = exchange_url;
211 0 : if (GNUNET_OK !=
212 0 : TALER_wallet_purse_deposit_verify (
213 : partner_url,
214 : purse_pub,
215 : &amount,
216 : h_denom_pub,
217 : phac,
218 : coin_pub,
219 : coin_sig))
220 : {
221 0 : GNUNET_break_op (0);
222 0 : return GNUNET_SYSERR;
223 : }
224 0 : return GNUNET_OK;
225 : }
226 :
227 :
228 : enum GNUNET_GenericReturnValue
229 0 : TALER_EXCHANGE_check_purse_econtract_conflict_ (
230 : const struct TALER_PurseContractSignatureP *ccontract_sig,
231 : const struct TALER_PurseContractPublicKeyP *purse_pub,
232 : const json_t *proof)
233 : {
234 : struct TALER_ContractDiffiePublicP contract_pub;
235 : struct TALER_PurseContractSignatureP contract_sig;
236 : struct GNUNET_HashCode h_econtract;
237 : struct GNUNET_JSON_Specification spec[] = {
238 0 : GNUNET_JSON_spec_fixed_auto ("h_econtract",
239 : &h_econtract),
240 0 : GNUNET_JSON_spec_fixed_auto ("econtract_sig",
241 : &contract_sig),
242 0 : GNUNET_JSON_spec_fixed_auto ("contract_pub",
243 : &contract_pub),
244 0 : GNUNET_JSON_spec_end ()
245 : };
246 :
247 0 : if (GNUNET_OK !=
248 0 : GNUNET_JSON_parse (proof,
249 : spec,
250 : NULL, NULL))
251 : {
252 0 : GNUNET_break_op (0);
253 0 : return GNUNET_SYSERR;
254 : }
255 0 : if (GNUNET_OK !=
256 0 : TALER_wallet_econtract_upload_verify2 (
257 : &h_econtract,
258 : &contract_pub,
259 : purse_pub,
260 : &contract_sig))
261 : {
262 0 : GNUNET_break_op (0);
263 0 : return GNUNET_SYSERR;
264 : }
265 0 : if (0 ==
266 0 : GNUNET_memcmp (&contract_sig,
267 : ccontract_sig))
268 : {
269 : /* Must be the SAME data, not a conflict! */
270 0 : GNUNET_break_op (0);
271 0 : return GNUNET_SYSERR;
272 : }
273 0 : return GNUNET_OK;
274 : }
275 :
276 :
277 : // FIXME: should be used... - #9422
278 : enum GNUNET_GenericReturnValue
279 0 : TALER_EXCHANGE_check_coin_denomination_conflict_ (
280 : const json_t *proof,
281 : const struct TALER_DenominationHashP *ch_denom_pub)
282 : {
283 : struct TALER_DenominationHashP h_denom_pub;
284 : struct GNUNET_JSON_Specification spec[] = {
285 0 : GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
286 : &h_denom_pub),
287 0 : GNUNET_JSON_spec_end ()
288 : };
289 :
290 0 : if (GNUNET_OK !=
291 0 : GNUNET_JSON_parse (proof,
292 : spec,
293 : NULL, NULL))
294 : {
295 0 : GNUNET_break_op (0);
296 0 : return GNUNET_SYSERR;
297 : }
298 0 : if (0 ==
299 0 : GNUNET_memcmp (ch_denom_pub,
300 : &h_denom_pub))
301 : {
302 0 : GNUNET_break_op (0);
303 0 : return GNUNET_OK;
304 : }
305 : /* indeed, proof with different denomination key provided */
306 0 : return GNUNET_OK;
307 : }
308 :
309 :
310 : enum GNUNET_GenericReturnValue
311 0 : TALER_EXCHANGE_get_min_denomination_ (
312 : const struct TALER_EXCHANGE_Keys *keys,
313 : struct TALER_Amount *min)
314 : {
315 0 : bool have_min = false;
316 0 : for (unsigned int i = 0; i<keys->num_denom_keys; i++)
317 : {
318 0 : const struct TALER_EXCHANGE_DenomPublicKey *dk = &keys->denom_keys[i];
319 :
320 0 : if (! have_min)
321 : {
322 0 : *min = dk->value;
323 0 : have_min = true;
324 0 : continue;
325 : }
326 0 : if (1 != TALER_amount_cmp (min,
327 : &dk->value))
328 0 : continue;
329 0 : *min = dk->value;
330 : }
331 0 : if (! have_min)
332 : {
333 0 : GNUNET_break (0);
334 0 : return GNUNET_SYSERR;
335 : }
336 0 : return GNUNET_OK;
337 : }
338 :
339 :
340 : enum GNUNET_GenericReturnValue
341 100 : TALER_EXCHANGE_verify_deposit_signature_ (
342 : const struct TALER_EXCHANGE_DepositContractDetail *dcd,
343 : const struct TALER_ExtensionPolicyHashP *ech,
344 : const struct TALER_MerchantWireHashP *h_wire,
345 : const struct TALER_EXCHANGE_CoinDepositDetail *cdd,
346 : const struct TALER_EXCHANGE_DenomPublicKey *dki)
347 : {
348 100 : if (GNUNET_OK !=
349 100 : TALER_wallet_deposit_verify (&cdd->amount,
350 : &dki->fees.deposit,
351 : h_wire,
352 : &dcd->h_contract_terms,
353 : &dcd->wallet_data_hash,
354 : &cdd->h_age_commitment,
355 : ech,
356 : &cdd->h_denom_pub,
357 : dcd->wallet_timestamp,
358 : &dcd->merchant_pub,
359 : dcd->refund_deadline,
360 : &cdd->coin_pub,
361 : &cdd->coin_sig))
362 : {
363 0 : GNUNET_break_op (0);
364 0 : TALER_LOG_WARNING ("Invalid coin signature on /deposit request!\n");
365 0 : TALER_LOG_DEBUG ("... amount_with_fee was %s\n",
366 : TALER_amount2s (&cdd->amount));
367 0 : TALER_LOG_DEBUG ("... deposit_fee was %s\n",
368 : TALER_amount2s (&dki->fees.deposit));
369 0 : return GNUNET_SYSERR;
370 : }
371 :
372 : /* check coin signature */
373 : {
374 100 : struct TALER_CoinPublicInfo coin_info = {
375 : .coin_pub = cdd->coin_pub,
376 : .denom_pub_hash = cdd->h_denom_pub,
377 : .denom_sig = cdd->denom_sig,
378 : .h_age_commitment = cdd->h_age_commitment,
379 : };
380 :
381 100 : if (GNUNET_YES !=
382 100 : TALER_test_coin_valid (&coin_info,
383 : &dki->key))
384 : {
385 0 : GNUNET_break_op (0);
386 0 : TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
387 0 : return GNUNET_SYSERR;
388 : }
389 : }
390 :
391 : /* Check coin does make a contribution */
392 100 : if (0 < TALER_amount_cmp (&dki->fees.deposit,
393 : &cdd->amount))
394 : {
395 0 : GNUNET_break_op (0);
396 0 : TALER_LOG_WARNING ("Deposit amount smaller than fee\n");
397 0 : return GNUNET_SYSERR;
398 : }
399 100 : return GNUNET_OK;
400 : }
401 :
402 :
403 : /**
404 : * Parse account restriction in @a jrest into @a rest.
405 : *
406 : * @param jresta array of account restrictions in JSON
407 : * @param[out] resta_len set to length of @a resta
408 : * @param[out] resta account restriction array to set
409 : * @return #GNUNET_OK on success
410 : */
411 : static enum GNUNET_GenericReturnValue
412 92 : parse_restrictions (const json_t *jresta,
413 : unsigned int *resta_len,
414 : struct TALER_EXCHANGE_AccountRestriction **resta)
415 : {
416 : size_t alen;
417 :
418 92 : if (! json_is_array (jresta))
419 : {
420 0 : GNUNET_break_op (0);
421 0 : return GNUNET_SYSERR;
422 : }
423 92 : alen = json_array_size (jresta);
424 92 : if (0 == alen)
425 : {
426 : /* no restrictions, perfectly OK */
427 92 : *resta = NULL;
428 92 : return GNUNET_OK;
429 : }
430 0 : *resta_len = (unsigned int) alen;
431 0 : GNUNET_assert (alen == *resta_len);
432 0 : *resta = GNUNET_new_array (*resta_len,
433 : struct TALER_EXCHANGE_AccountRestriction);
434 0 : for (unsigned int i = 0; i<*resta_len; i++)
435 : {
436 0 : const json_t *jr = json_array_get (jresta,
437 : i);
438 0 : struct TALER_EXCHANGE_AccountRestriction *ar = &(*resta)[i];
439 0 : const char *type = json_string_value (json_object_get (jr,
440 : "type"));
441 :
442 0 : if (NULL == type)
443 : {
444 0 : GNUNET_break (0);
445 0 : goto fail;
446 : }
447 0 : if (0 == strcmp (type,
448 : "deny"))
449 : {
450 0 : ar->type = TALER_EXCHANGE_AR_DENY;
451 0 : continue;
452 : }
453 0 : if (0 == strcmp (type,
454 : "regex"))
455 0 : {
456 : const char *regex;
457 : const char *hint;
458 : struct GNUNET_JSON_Specification spec[] = {
459 0 : GNUNET_JSON_spec_string (
460 : "payto_regex",
461 : ®ex),
462 0 : GNUNET_JSON_spec_string (
463 : "human_hint",
464 : &hint),
465 0 : GNUNET_JSON_spec_mark_optional (
466 : GNUNET_JSON_spec_json (
467 : "human_hint_i18n",
468 : &ar->details.regex.human_hint_i18n),
469 : NULL),
470 0 : GNUNET_JSON_spec_end ()
471 : };
472 :
473 0 : if (GNUNET_OK !=
474 0 : GNUNET_JSON_parse (jr,
475 : spec,
476 : NULL, NULL))
477 : {
478 : /* bogus reply */
479 0 : GNUNET_break_op (0);
480 0 : goto fail;
481 : }
482 0 : ar->type = TALER_EXCHANGE_AR_REGEX;
483 0 : ar->details.regex.posix_egrep = GNUNET_strdup (regex);
484 0 : ar->details.regex.human_hint = GNUNET_strdup (hint);
485 0 : continue;
486 : }
487 : /* unsupported type */
488 0 : GNUNET_break (0);
489 0 : return GNUNET_SYSERR;
490 : }
491 0 : return GNUNET_OK;
492 0 : fail:
493 0 : GNUNET_free (*resta);
494 0 : *resta_len = 0;
495 0 : return GNUNET_SYSERR;
496 : }
497 :
498 :
499 : enum GNUNET_GenericReturnValue
500 42 : TALER_EXCHANGE_parse_accounts (
501 : const struct TALER_MasterPublicKeyP *master_pub,
502 : const json_t *accounts,
503 : unsigned int was_length,
504 : struct TALER_EXCHANGE_WireAccount was[static was_length])
505 42 : {
506 42 : memset (was,
507 : 0,
508 : sizeof (struct TALER_EXCHANGE_WireAccount) * was_length);
509 42 : GNUNET_assert (was_length ==
510 : json_array_size (accounts));
511 42 : for (unsigned int i = 0;
512 88 : i<was_length;
513 46 : i++)
514 : {
515 46 : struct TALER_EXCHANGE_WireAccount *wa = &was[i];
516 : struct TALER_FullPayto payto_uri;
517 46 : const char *conversion_url = NULL;
518 46 : const char *open_banking_gateway = NULL;
519 46 : const char *wire_transfer_gateway = NULL;
520 46 : const char *bank_label = NULL;
521 46 : int64_t priority = 0;
522 : const json_t *credit_restrictions;
523 : const json_t *debit_restrictions;
524 : struct GNUNET_JSON_Specification spec_account[] = {
525 46 : TALER_JSON_spec_full_payto_uri ("payto_uri",
526 : &payto_uri),
527 46 : GNUNET_JSON_spec_mark_optional (
528 : TALER_JSON_spec_web_url ("conversion_url",
529 : &conversion_url),
530 : NULL),
531 46 : GNUNET_JSON_spec_mark_optional (
532 : GNUNET_JSON_spec_string ("open_banking_gateway",
533 : &open_banking_gateway),
534 : NULL),
535 46 : GNUNET_JSON_spec_mark_optional (
536 : GNUNET_JSON_spec_string ("wire_transfer_gateway",
537 : &wire_transfer_gateway),
538 : NULL),
539 46 : GNUNET_JSON_spec_mark_optional (
540 : GNUNET_JSON_spec_int64 ("priority",
541 : &priority),
542 : NULL),
543 46 : GNUNET_JSON_spec_mark_optional (
544 : GNUNET_JSON_spec_string ("bank_label",
545 : &bank_label),
546 : NULL),
547 46 : GNUNET_JSON_spec_array_const ("credit_restrictions",
548 : &credit_restrictions),
549 46 : GNUNET_JSON_spec_array_const ("debit_restrictions",
550 : &debit_restrictions),
551 46 : GNUNET_JSON_spec_fixed_auto ("master_sig",
552 : &wa->master_sig),
553 46 : GNUNET_JSON_spec_end ()
554 : };
555 : json_t *account;
556 :
557 46 : account = json_array_get (accounts,
558 : i);
559 46 : if (GNUNET_OK !=
560 46 : GNUNET_JSON_parse (account,
561 : spec_account,
562 : NULL, NULL))
563 : {
564 : /* bogus reply */
565 0 : GNUNET_break_op (0);
566 0 : return GNUNET_SYSERR;
567 : }
568 46 : if ( (NULL != master_pub) &&
569 92 : (! ( ( (NULL == open_banking_gateway) &&
570 92 : (NULL == wire_transfer_gateway) &&
571 : (GNUNET_OK ==
572 46 : TALER_exchange_wire_signature_check32 (
573 : payto_uri,
574 : conversion_url,
575 : debit_restrictions,
576 : credit_restrictions,
577 : master_pub,
578 46 : &wa->master_sig)) ) ||
579 : (GNUNET_OK ==
580 46 : TALER_exchange_wire_signature_check (
581 : payto_uri,
582 : conversion_url,
583 : open_banking_gateway,
584 : wire_transfer_gateway,
585 : debit_restrictions,
586 : credit_restrictions,
587 : master_pub,
588 46 : &wa->master_sig)) ) ) )
589 : {
590 : /* bogus reply */
591 0 : GNUNET_break_op (0);
592 0 : return GNUNET_SYSERR;
593 : }
594 46 : if ( (GNUNET_OK !=
595 46 : parse_restrictions (credit_restrictions,
596 : &wa->credit_restrictions_length,
597 46 : &wa->credit_restrictions)) ||
598 : (GNUNET_OK !=
599 46 : parse_restrictions (debit_restrictions,
600 : &wa->debit_restrictions_length,
601 : &wa->debit_restrictions)) )
602 : {
603 : /* bogus reply */
604 0 : GNUNET_break_op (0);
605 0 : return GNUNET_SYSERR;
606 : }
607 : wa->fpayto_uri.full_payto
608 46 : = GNUNET_strdup (payto_uri.full_payto);
609 46 : wa->priority = priority;
610 46 : if (NULL != conversion_url)
611 0 : wa->conversion_url = GNUNET_strdup (conversion_url);
612 46 : if (NULL != open_banking_gateway)
613 0 : wa->open_banking_gateway = GNUNET_strdup (open_banking_gateway);
614 46 : if (NULL != wire_transfer_gateway)
615 0 : wa->wire_transfer_gateway = GNUNET_strdup (wire_transfer_gateway);
616 46 : if (NULL != bank_label)
617 4 : wa->bank_label = GNUNET_strdup (bank_label);
618 : } /* end 'for all accounts */
619 42 : return GNUNET_OK;
620 : }
621 :
622 :
623 : /**
624 : * Free array of account restrictions.
625 : *
626 : * @param ar_len length of @a ar
627 : * @param[in] ar array to free contents of (but not @a ar itself)
628 : */
629 : static void
630 92 : free_restrictions (unsigned int ar_len,
631 : struct TALER_EXCHANGE_AccountRestriction ar[static ar_len])
632 92 : {
633 92 : for (unsigned int i = 0; i<ar_len; i++)
634 : {
635 0 : struct TALER_EXCHANGE_AccountRestriction *a = &ar[i];
636 0 : switch (a->type)
637 : {
638 0 : case TALER_EXCHANGE_AR_INVALID:
639 0 : GNUNET_break (0);
640 0 : break;
641 0 : case TALER_EXCHANGE_AR_DENY:
642 0 : break;
643 0 : case TALER_EXCHANGE_AR_REGEX:
644 0 : GNUNET_free (ar->details.regex.posix_egrep);
645 0 : GNUNET_free (ar->details.regex.human_hint);
646 0 : json_decref (ar->details.regex.human_hint_i18n);
647 0 : break;
648 : }
649 : }
650 92 : }
651 :
652 :
653 : void
654 42 : TALER_EXCHANGE_free_accounts (
655 : unsigned int was_len,
656 : struct TALER_EXCHANGE_WireAccount was[static was_len])
657 42 : {
658 88 : for (unsigned int i = 0; i<was_len; i++)
659 : {
660 46 : struct TALER_EXCHANGE_WireAccount *wa = &was[i];
661 :
662 46 : GNUNET_free (wa->fpayto_uri.full_payto);
663 46 : GNUNET_free (wa->conversion_url);
664 46 : GNUNET_free (wa->open_banking_gateway);
665 46 : GNUNET_free (wa->wire_transfer_gateway);
666 46 : GNUNET_free (wa->bank_label);
667 46 : free_restrictions (wa->credit_restrictions_length,
668 : wa->credit_restrictions);
669 46 : GNUNET_array_grow (wa->credit_restrictions,
670 : wa->credit_restrictions_length,
671 : 0);
672 46 : free_restrictions (wa->debit_restrictions_length,
673 : wa->debit_restrictions);
674 46 : GNUNET_array_grow (wa->debit_restrictions,
675 : wa->debit_restrictions_length,
676 : 0);
677 : }
678 42 : }
679 :
680 :
681 : enum GNUNET_GenericReturnValue
682 0 : TALER_EXCHANGE_keys_test_account_allowed (
683 : const struct TALER_EXCHANGE_Keys *keys,
684 : bool check_credit,
685 : const struct TALER_NormalizedPayto payto_uri)
686 : {
687 : /* For all accounts of the exchange */
688 0 : for (unsigned int i = 0; i<keys->accounts_len; i++)
689 : {
690 0 : const struct TALER_EXCHANGE_WireAccount *account
691 0 : = &keys->accounts[i];
692 :
693 : /* KYC auth transfers are never supported with conversion */
694 0 : if (NULL != account->conversion_url)
695 0 : continue;
696 : /* filter by source account by credit_restrictions */
697 0 : if (GNUNET_YES !=
698 0 : TALER_EXCHANGE_test_account_allowed (account,
699 : check_credit,
700 : payto_uri))
701 0 : continue;
702 : /* exchange account is allowed, add it */
703 0 : return true;
704 : }
705 0 : return false;
706 : }
707 :
708 :
709 : /**
710 : * We received an #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS response code.
711 : * Parse the JSON response and initialize the @a uflr object.
712 : *
713 : * @param[out] uflr data structure to initialize
714 : * @param j JSON response to parse
715 : * @return #GNUNET_OK on success
716 : */
717 : enum GNUNET_GenericReturnValue
718 18 : TALER_EXCHANGE_parse_451 (struct TALER_EXCHANGE_KycNeededRedirect *uflr,
719 : const json_t *j)
720 : {
721 : struct GNUNET_JSON_Specification spec[] = {
722 18 : GNUNET_JSON_spec_fixed_auto (
723 : "h_payto",
724 : &uflr->h_payto),
725 18 : GNUNET_JSON_spec_uint64 (
726 : "requirement_row",
727 : &uflr->requirement_row),
728 18 : GNUNET_JSON_spec_mark_optional (
729 18 : GNUNET_JSON_spec_fixed_auto (
730 : "account_pub",
731 : &uflr->account_pub),
732 : NULL),
733 18 : GNUNET_JSON_spec_mark_optional (
734 : GNUNET_JSON_spec_bool (
735 : "bad_kyc_auth",
736 : &uflr->bad_kyc_auth),
737 : NULL),
738 18 : GNUNET_JSON_spec_end ()
739 : };
740 :
741 18 : if (GNUNET_OK !=
742 18 : GNUNET_JSON_parse (j,
743 : spec,
744 : NULL,
745 : NULL))
746 : {
747 0 : GNUNET_break_op (0);
748 0 : return GNUNET_SYSERR;
749 : }
750 18 : return GNUNET_OK;
751 : }
752 :
753 :
754 : /* end of exchange_api_common.c */
|