Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 2026 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU Lesser 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 <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file src/util/util.c
18 : * @brief small helpers
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <string.h>
23 : #include "taler/taler_merchant_util.h"
24 : #include <taler/taler_json_lib.h>
25 : #include <gnunet/gnunet_json_lib.h>
26 :
27 :
28 : bool
29 119 : TALER_MERCHANT_taxes_array_valid (const json_t *taxes)
30 : {
31 : json_t *tax;
32 : size_t idx;
33 :
34 119 : if (! json_is_array (taxes))
35 0 : return false;
36 119 : json_array_foreach (taxes, idx, tax)
37 : {
38 : struct TALER_Amount amount;
39 : const char *name;
40 : struct GNUNET_JSON_Specification spec[] = {
41 0 : GNUNET_JSON_spec_string ("name",
42 : &name),
43 0 : TALER_JSON_spec_amount_any ("tax",
44 : &amount),
45 0 : GNUNET_JSON_spec_end ()
46 : };
47 : enum GNUNET_GenericReturnValue res;
48 : const char *ename;
49 : unsigned int eline;
50 :
51 0 : res = GNUNET_JSON_parse (tax,
52 : spec,
53 : &ename,
54 : &eline);
55 0 : if (GNUNET_OK != res)
56 : {
57 0 : GNUNET_break_op (0);
58 0 : return false;
59 : }
60 : }
61 119 : return true;
62 : }
63 :
64 :
65 : bool
66 63 : TALER_MERCHANT_payment_method_valid (
67 : const char *method)
68 : {
69 63 : if ( (0 == strlen (method)) ||
70 62 : (0 == strcasecmp ("taler",
71 : method)) )
72 : {
73 6 : GNUNET_break_op (0);
74 6 : return false;
75 : }
76 283 : for (const char *c = method; '\0' != *c; c++)
77 227 : if ( (! isalnum ((unsigned char) *c)) &&
78 1 : ('-' != *c) )
79 : {
80 1 : GNUNET_break_op (0);
81 1 : return false;
82 : }
83 56 : return true;
84 : }
85 :
86 :
87 : bool
88 33 : TALER_MERCHANT_amount_external_valid (
89 : const json_t *amount_external)
90 : {
91 : struct TALER_Amount first;
92 33 : bool have_first = false;
93 : json_t *entry;
94 : size_t idx;
95 :
96 33 : if (! json_is_array (amount_external))
97 0 : return false;
98 58 : json_array_foreach (amount_external, idx, entry)
99 : {
100 : const char *method;
101 : const char *id;
102 : struct TALER_Amount ext_amount;
103 : struct GNUNET_JSON_Specification spec[] = {
104 37 : GNUNET_JSON_spec_string ("method",
105 : &method),
106 37 : GNUNET_JSON_spec_string ("id",
107 : &id),
108 37 : TALER_JSON_spec_amount_any ("amount",
109 : &ext_amount),
110 37 : GNUNET_JSON_spec_end ()
111 : };
112 :
113 37 : if (GNUNET_OK !=
114 37 : GNUNET_JSON_parse (entry,
115 : spec,
116 : NULL,
117 : NULL))
118 : {
119 2 : GNUNET_break_op (0);
120 12 : return false;
121 : }
122 35 : if (! TALER_MERCHANT_payment_method_valid (method))
123 5 : return false;
124 30 : if (0 == strlen (id))
125 : {
126 0 : GNUNET_break_op (0);
127 0 : return false;
128 : }
129 30 : if (! have_first)
130 : {
131 26 : first = ext_amount;
132 26 : have_first = true;
133 : }
134 4 : else if (GNUNET_OK !=
135 4 : TALER_amount_cmp_currency (&ext_amount,
136 : &first))
137 : {
138 : /* the entries have to agree on a currency among themselves */
139 1 : GNUNET_break_op (0);
140 1 : return false;
141 : }
142 31 : for (size_t j = 0; j < idx; j++)
143 : {
144 : const char *other_id
145 3 : = json_string_value (
146 3 : json_object_get (json_array_get (amount_external,
147 : j),
148 : "id"));
149 :
150 3 : if ( (NULL != other_id) &&
151 3 : (0 == strcmp (id,
152 : other_id)) )
153 : {
154 1 : GNUNET_break_op (0);
155 1 : return false;
156 : }
157 : }
158 : {
159 : const char *key;
160 : json_t *value;
161 :
162 118 : json_object_foreach (entry, key, value)
163 : {
164 93 : if ( (json_is_object (value)) ||
165 90 : (json_is_array (value)) ||
166 90 : (json_is_real (value)) )
167 : {
168 3 : GNUNET_break_op (0);
169 3 : return false;
170 : }
171 : }
172 : }
173 : }
174 21 : return true;
175 : }
176 :
177 :
178 : bool
179 22 : TALER_MERCHANT_amount_external_currency_valid (
180 : const json_t *amount_external,
181 : const struct TALER_Amount *amount)
182 : {
183 : struct TALER_Amount ext_amount;
184 : struct GNUNET_JSON_Specification spec[] = {
185 22 : TALER_JSON_spec_amount_any ("amount",
186 : &ext_amount),
187 22 : GNUNET_JSON_spec_end ()
188 : };
189 :
190 22 : if (0 == json_array_size (amount_external))
191 0 : return true; /* no external payment to agree with */
192 22 : if (GNUNET_OK !=
193 22 : GNUNET_JSON_parse (json_array_get (amount_external,
194 : 0),
195 : spec,
196 : NULL,
197 : NULL))
198 : {
199 0 : GNUNET_break_op (0);
200 0 : return false;
201 : }
202 22 : return (GNUNET_OK ==
203 22 : TALER_amount_cmp_currency (&ext_amount,
204 : amount));
205 : }
206 :
207 :
208 : bool
209 19 : TALER_MERCHANT_amount_external_total_valid (
210 : const json_t *amount_external,
211 : const struct TALER_Amount *amount)
212 : {
213 19 : struct TALER_Amount total = *amount;
214 : json_t *entry;
215 : size_t idx;
216 :
217 37 : json_array_foreach ((json_t *) amount_external, idx, entry)
218 : {
219 : struct TALER_Amount ext_amount;
220 : struct GNUNET_JSON_Specification spec[] = {
221 20 : TALER_JSON_spec_amount_any ("amount",
222 : &ext_amount),
223 20 : GNUNET_JSON_spec_end ()
224 : };
225 :
226 20 : if (GNUNET_OK !=
227 20 : GNUNET_JSON_parse (entry,
228 : spec,
229 : NULL,
230 : NULL))
231 : {
232 0 : GNUNET_break_op (0);
233 2 : return false;
234 : }
235 20 : if (0 >
236 20 : TALER_amount_add (&total,
237 : &total,
238 : &ext_amount))
239 : {
240 : /* The order total would not be representable; refusing here
241 : keeps us from storing an order whose total can never be
242 : computed again. */
243 2 : GNUNET_break_op (0);
244 2 : return false;
245 : }
246 : }
247 17 : return true;
248 : }
249 :
250 :
251 : enum TALER_MERCHANT_ContractTokenKind
252 11 : TALER_MERCHANT_contract_token_kind_from_string (const char *str)
253 : {
254 11 : if (NULL == str)
255 : {
256 0 : GNUNET_break (0);
257 0 : return TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID;
258 : }
259 11 : if (0 == strcmp ("subscription",
260 : str))
261 8 : return TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION;
262 3 : if (0 == strcmp ("discount",
263 : str))
264 3 : return TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT;
265 0 : return TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID;
266 : }
|