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