Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 2016-2024 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or
6 : modify it under the terms of the GNU General Public License
7 : as published by the Free Software Foundation; either version 3,
8 : or (at your option) any later version.
9 :
10 : TALER is distributed in the hope that it will be useful,
11 : but 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,
17 : see <http://www.gnu.org/licenses/>
18 : */
19 : /**
20 : * @file bank-lib/fakebank_tbi_post_withdrawal_operation.c
21 : * @brief library that fakes being a Taler bank for testcases
22 : * @author Christian Grothoff <christian@grothoff.org>
23 : */
24 : #include <pthread.h>
25 : #include "taler/taler_fakebank_lib.h"
26 : #include "taler/taler_bank_service.h"
27 : #include "taler/taler_mhd_lib.h"
28 : #include <gnunet/gnunet_mhd_compat.h>
29 : #include <gnunet/gnunet_mhd_lib.h>
30 : #include "fakebank.h"
31 : #include "fakebank_common_lookup.h"
32 : #include "fakebank_tbi_post_withdrawal_operation.h"
33 :
34 :
35 : /**
36 : * Execute POST /withdrawal-operation/ request.
37 : *
38 : * @param h our handle
39 : * @param connection the connection
40 : * @param wopid the withdrawal operation identifier
41 : * @param reserve_pub public key of the reserve
42 : * @param exchange_payto_uri payto://-URI of the exchange
43 : * @param amount chosen by the client, or NULL to use the
44 : * pre-determined amount
45 : * @return MHD result code
46 : */
47 : static enum MHD_Result
48 0 : do_post_withdrawal (
49 : struct TALER_FAKEBANK_Handle *h,
50 : struct MHD_Connection *connection,
51 : const char *wopid,
52 : const struct TALER_ReservePublicKeyP *reserve_pub,
53 : const struct TALER_FullPayto exchange_payto_uri,
54 : const struct TALER_Amount *amount)
55 : {
56 : struct WithdrawalOperation *wo;
57 : char *credit_name;
58 : struct Account *credit_account;
59 : const char *status_string;
60 :
61 0 : GNUNET_assert (0 ==
62 : pthread_mutex_lock (&h->big_lock));
63 0 : wo = TALER_FAKEBANK_lookup_withdrawal_operation_ (h,
64 : wopid);
65 0 : if (NULL == wo)
66 : {
67 0 : GNUNET_assert (0 ==
68 : pthread_mutex_unlock (&h->big_lock));
69 0 : return TALER_MHD_reply_with_error (
70 : connection,
71 : MHD_HTTP_NOT_FOUND,
72 : TALER_EC_BANK_TRANSACTION_NOT_FOUND,
73 : wopid);
74 : }
75 0 : if (wo->aborted)
76 : {
77 0 : GNUNET_assert (0 ==
78 : pthread_mutex_unlock (&h->big_lock));
79 0 : return TALER_MHD_reply_with_error (
80 : connection,
81 : MHD_HTTP_CONFLICT,
82 : TALER_EC_BANK_UPDATE_ABORT_CONFLICT,
83 : wopid);
84 : }
85 0 : if ( (wo->selection_done) &&
86 0 : (0 != GNUNET_memcmp (&wo->reserve_pub,
87 : reserve_pub)) )
88 : {
89 0 : GNUNET_assert (0 ==
90 : pthread_mutex_unlock (&h->big_lock));
91 0 : return TALER_MHD_reply_with_error (
92 : connection,
93 : MHD_HTTP_CONFLICT,
94 : TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT,
95 : "reserve public key changed");
96 : }
97 : {
98 : /* check if reserve_pub is already in use */
99 : const struct GNUNET_PeerIdentity *pid;
100 : bool duplicate;
101 :
102 0 : pid = (const struct GNUNET_PeerIdentity *) reserve_pub;
103 0 : GNUNET_assert (0 == pthread_mutex_lock (&h->rpubs_lock));
104 0 : duplicate = GNUNET_CONTAINER_multipeermap_contains (h->rpubs,
105 : pid);
106 0 : GNUNET_assert (0 == pthread_mutex_unlock (&h->rpubs_lock));
107 0 : if (duplicate)
108 : {
109 0 : GNUNET_assert (0 ==
110 : pthread_mutex_unlock (&h->big_lock));
111 0 : return TALER_MHD_reply_with_error (connection,
112 : MHD_HTTP_CONFLICT,
113 : TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT,
114 : NULL);
115 : }
116 : }
117 0 : credit_name = TALER_xtalerbank_account_from_payto (exchange_payto_uri);
118 0 : if (NULL == credit_name)
119 : {
120 0 : GNUNET_break_op (0);
121 0 : GNUNET_assert (0 ==
122 : pthread_mutex_unlock (&h->big_lock));
123 0 : return TALER_MHD_reply_with_error (connection,
124 : MHD_HTTP_BAD_REQUEST,
125 : TALER_EC_GENERIC_PAYTO_URI_MALFORMED,
126 : NULL);
127 : }
128 0 : credit_account = TALER_FAKEBANK_lookup_account_ (h,
129 : credit_name,
130 : NULL);
131 0 : if (NULL == credit_account)
132 : {
133 : enum MHD_Result res;
134 :
135 0 : GNUNET_break_op (0);
136 0 : GNUNET_assert (0 ==
137 : pthread_mutex_unlock (&h->big_lock));
138 0 : res = TALER_MHD_reply_with_error (connection,
139 : MHD_HTTP_NOT_FOUND,
140 : TALER_EC_BANK_UNKNOWN_ACCOUNT,
141 : credit_name);
142 0 : GNUNET_free (credit_name);
143 0 : return res;
144 : }
145 0 : GNUNET_free (credit_name);
146 0 : if ( (NULL != wo->exchange_account) &&
147 0 : (credit_account != wo->exchange_account) )
148 : {
149 0 : GNUNET_assert (0 ==
150 : pthread_mutex_unlock (&h->big_lock));
151 0 : return TALER_MHD_reply_with_error (
152 : connection,
153 : MHD_HTTP_CONFLICT,
154 : TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT,
155 : "exchange account changed");
156 : }
157 0 : if ( (NULL != wo->amount) &&
158 0 : (NULL != amount) &&
159 0 : (0 != TALER_amount_cmp (wo->amount,
160 : amount)) )
161 : {
162 0 : GNUNET_assert (0 ==
163 : pthread_mutex_unlock (&h->big_lock));
164 0 : return TALER_MHD_reply_with_error (
165 : connection,
166 : MHD_HTTP_CONFLICT,
167 : TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT,
168 : "amount changed");
169 : }
170 0 : if (NULL == wo->amount)
171 : {
172 0 : if (NULL == amount)
173 : {
174 0 : GNUNET_assert (0 ==
175 : pthread_mutex_unlock (&h->big_lock));
176 0 : return TALER_MHD_reply_with_error (
177 : connection,
178 : MHD_HTTP_BAD_REQUEST,
179 : TALER_EC_BANK_POST_WITHDRAWAL_OPERATION_REQUIRED,
180 : "amount missing");
181 : }
182 : else
183 : {
184 0 : wo->amount = GNUNET_new (struct TALER_Amount);
185 0 : *wo->amount = *amount;
186 : }
187 : }
188 0 : GNUNET_assert (NULL != wo->amount);
189 0 : wo->exchange_account = credit_account;
190 0 : wo->reserve_pub = *reserve_pub;
191 0 : wo->selection_done = true;
192 0 : GNUNET_assert (0 ==
193 : pthread_mutex_unlock (&h->big_lock));
194 0 : if (wo->aborted)
195 0 : status_string = "aborted";
196 0 : else if (wo->confirmation_done)
197 0 : status_string = "confirmed";
198 : else
199 0 : status_string = "selected";
200 0 : return TALER_MHD_REPLY_JSON_PACK (
201 : connection,
202 : MHD_HTTP_OK,
203 : // FIXME: Deprecated field, should be deleted in the future.
204 : GNUNET_JSON_pack_bool ("transfer_done",
205 : wo->confirmation_done),
206 : GNUNET_JSON_pack_string ("status",
207 : status_string));
208 : }
209 :
210 :
211 : enum MHD_Result
212 0 : TALER_FAKEBANK_tbi_post_withdrawal (
213 : struct TALER_FAKEBANK_Handle *h,
214 : struct MHD_Connection *connection,
215 : const char *wopid,
216 : const void *upload_data,
217 : size_t *upload_data_size,
218 : void **con_cls)
219 : {
220 0 : struct ConnectionContext *cc = *con_cls;
221 : enum GNUNET_MHD_PostResult pr;
222 : json_t *json;
223 : enum MHD_Result res;
224 :
225 0 : if (NULL == cc)
226 : {
227 0 : cc = GNUNET_new (struct ConnectionContext);
228 0 : cc->ctx_cleaner = &GNUNET_MHD_post_parser_cleanup;
229 0 : *con_cls = cc;
230 : }
231 0 : pr = GNUNET_MHD_post_parser (REQUEST_BUFFER_MAX,
232 : connection,
233 : &cc->ctx,
234 : upload_data,
235 : upload_data_size,
236 : &json);
237 0 : switch (pr)
238 : {
239 0 : case GNUNET_MHD_PR_OUT_OF_MEMORY:
240 0 : GNUNET_break (0);
241 0 : return MHD_NO;
242 0 : case GNUNET_MHD_PR_CONTINUE:
243 0 : return MHD_YES;
244 0 : case GNUNET_MHD_PR_REQUEST_TOO_LARGE:
245 0 : GNUNET_break (0);
246 0 : return MHD_NO;
247 0 : case GNUNET_MHD_PR_JSON_INVALID:
248 0 : GNUNET_break (0);
249 0 : return MHD_NO;
250 0 : case GNUNET_MHD_PR_SUCCESS:
251 0 : break;
252 : }
253 :
254 : {
255 : struct TALER_ReservePublicKeyP reserve_pub;
256 : struct TALER_FullPayto exchange_payto_url;
257 : enum GNUNET_GenericReturnValue ret;
258 : struct TALER_Amount amount;
259 : bool amount_missing;
260 : struct TALER_Amount *amount_ptr;
261 : struct GNUNET_JSON_Specification spec[] = {
262 0 : GNUNET_JSON_spec_fixed_auto ("reserve_pub",
263 : &reserve_pub),
264 0 : TALER_JSON_spec_full_payto_uri ("selected_exchange",
265 : &exchange_payto_url),
266 0 : GNUNET_JSON_spec_mark_optional (
267 : TALER_JSON_spec_amount ("amount",
268 0 : h->currency,
269 : &amount),
270 : &amount_missing),
271 0 : GNUNET_JSON_spec_end ()
272 : };
273 :
274 0 : if (GNUNET_OK !=
275 0 : (ret = TALER_MHD_parse_json_data (connection,
276 : json,
277 : spec)))
278 : {
279 0 : GNUNET_break_op (0);
280 0 : json_decref (json);
281 0 : return (GNUNET_NO == ret) ? MHD_YES : MHD_NO;
282 : }
283 :
284 0 : amount_ptr = amount_missing ? NULL : &amount;
285 :
286 0 : res = do_post_withdrawal (h,
287 : connection,
288 : wopid,
289 : &reserve_pub,
290 : exchange_payto_url,
291 : amount_ptr);
292 : }
293 0 : json_decref (json);
294 0 : return res;
295 : }
|