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 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 (connection,
70 : MHD_HTTP_NOT_FOUND,
71 : TALER_EC_BANK_TRANSACTION_NOT_FOUND,
72 : wopid);
73 : }
74 0 : if (wo->aborted)
75 : {
76 0 : GNUNET_assert (0 ==
77 : pthread_mutex_unlock (&h->big_lock));
78 0 : return TALER_MHD_reply_with_error (connection,
79 : MHD_HTTP_CONFLICT,
80 : TALER_EC_BANK_UPDATE_ABORT_CONFLICT,
81 : wopid);
82 : }
83 0 : if ( (wo->selection_done) &&
84 0 : (0 != GNUNET_memcmp (&wo->reserve_pub,
85 : reserve_pub)) )
86 : {
87 0 : GNUNET_assert (0 ==
88 : pthread_mutex_unlock (&h->big_lock));
89 0 : return TALER_MHD_reply_with_error (connection,
90 : MHD_HTTP_CONFLICT,
91 : TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT,
92 : "reserve public key changed");
93 : }
94 : {
95 : /* check if reserve_pub is already in use */
96 : const struct GNUNET_PeerIdentity *pid;
97 :
98 0 : pid = (const struct GNUNET_PeerIdentity *) &wo->reserve_pub;
99 0 : if (GNUNET_CONTAINER_multipeermap_contains (h->rpubs,
100 : pid))
101 : {
102 0 : GNUNET_assert (0 ==
103 : pthread_mutex_unlock (&h->big_lock));
104 0 : return TALER_MHD_reply_with_error (connection,
105 : MHD_HTTP_CONFLICT,
106 : TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT,
107 : NULL);
108 : }
109 : }
110 0 : credit_name = TALER_xtalerbank_account_from_payto (exchange_payto_uri);
111 0 : if (NULL == credit_name)
112 : {
113 0 : GNUNET_break_op (0);
114 0 : GNUNET_assert (0 ==
115 : pthread_mutex_unlock (&h->big_lock));
116 0 : return TALER_MHD_reply_with_error (connection,
117 : MHD_HTTP_BAD_REQUEST,
118 : TALER_EC_GENERIC_PAYTO_URI_MALFORMED,
119 : NULL);
120 : }
121 0 : credit_account = TALER_FAKEBANK_lookup_account_ (h,
122 : credit_name,
123 : NULL);
124 0 : if (NULL == credit_account)
125 : {
126 : MHD_RESULT res;
127 :
128 0 : GNUNET_break_op (0);
129 0 : GNUNET_assert (0 ==
130 : pthread_mutex_unlock (&h->big_lock));
131 0 : res = TALER_MHD_reply_with_error (connection,
132 : MHD_HTTP_NOT_FOUND,
133 : TALER_EC_BANK_UNKNOWN_ACCOUNT,
134 : credit_name);
135 0 : GNUNET_free (credit_name);
136 0 : return res;
137 : }
138 0 : GNUNET_free (credit_name);
139 0 : if ( (NULL != wo->exchange_account) &&
140 0 : (credit_account != wo->exchange_account) )
141 : {
142 0 : GNUNET_assert (0 ==
143 : pthread_mutex_unlock (&h->big_lock));
144 0 : return TALER_MHD_reply_with_error (connection,
145 : MHD_HTTP_CONFLICT,
146 : TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT,
147 : "exchange account changed");
148 : }
149 0 : if ( (NULL != wo->amount) && (NULL != amount) && (0 != TALER_amount_cmp (wo->
150 : amount,
151 : amount)) )
152 : {
153 0 : GNUNET_assert (0 ==
154 : pthread_mutex_unlock (&h->big_lock));
155 0 : return TALER_MHD_reply_with_error (connection,
156 : MHD_HTTP_CONFLICT,
157 : TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT,
158 : "amount changed");
159 : }
160 0 : if (NULL == wo->amount)
161 : {
162 0 : if (NULL == amount)
163 : {
164 0 : GNUNET_assert (0 ==
165 : pthread_mutex_unlock (&h->big_lock));
166 0 : return TALER_MHD_reply_with_error (connection,
167 : MHD_HTTP_BAD_REQUEST,
168 : TALER_EC_BANK_POST_WITHDRAWAL_OPERATION_REQUIRED,
169 : "amount missing");
170 : }
171 : else
172 : {
173 0 : wo->amount = GNUNET_new (struct TALER_Amount);
174 0 : *wo->amount = *amount;
175 : }
176 : }
177 0 : GNUNET_assert (NULL != wo->amount);
178 0 : wo->exchange_account = credit_account;
179 0 : wo->reserve_pub = *reserve_pub;
180 0 : wo->selection_done = true;
181 0 : GNUNET_assert (0 ==
182 : pthread_mutex_unlock (&h->big_lock));
183 0 : if (wo->aborted)
184 0 : status_string = "aborted";
185 0 : else if (wo->confirmation_done)
186 0 : status_string = "confirmed";
187 : else
188 0 : status_string = "selected";
189 0 : return TALER_MHD_REPLY_JSON_PACK (
190 : connection,
191 : MHD_HTTP_OK,
192 : // FIXME: Deprecated field, should be deleted in the future.
193 : GNUNET_JSON_pack_bool ("transfer_done",
194 : wo->confirmation_done),
195 : GNUNET_JSON_pack_string ("status",
196 : status_string));
197 : }
198 :
199 :
200 : MHD_RESULT
201 0 : TALER_FAKEBANK_tbi_post_withdrawal (
202 : struct TALER_FAKEBANK_Handle *h,
203 : struct MHD_Connection *connection,
204 : const char *wopid,
205 : const void *upload_data,
206 : size_t *upload_data_size,
207 : void **con_cls)
208 : {
209 0 : struct ConnectionContext *cc = *con_cls;
210 : enum GNUNET_MHD_PostResult pr;
211 : json_t *json;
212 : MHD_RESULT res;
213 :
214 0 : if (NULL == cc)
215 : {
216 0 : cc = GNUNET_new (struct ConnectionContext);
217 0 : cc->ctx_cleaner = &GNUNET_MHD_post_parser_cleanup;
218 0 : *con_cls = cc;
219 : }
220 0 : pr = GNUNET_MHD_post_parser (REQUEST_BUFFER_MAX,
221 : connection,
222 : &cc->ctx,
223 : upload_data,
224 : upload_data_size,
225 : &json);
226 0 : switch (pr)
227 : {
228 0 : case GNUNET_MHD_PR_OUT_OF_MEMORY:
229 0 : GNUNET_break (0);
230 0 : return MHD_NO;
231 0 : case GNUNET_MHD_PR_CONTINUE:
232 0 : return MHD_YES;
233 0 : case GNUNET_MHD_PR_REQUEST_TOO_LARGE:
234 0 : GNUNET_break (0);
235 0 : return MHD_NO;
236 0 : case GNUNET_MHD_PR_JSON_INVALID:
237 0 : GNUNET_break (0);
238 0 : return MHD_NO;
239 0 : case GNUNET_MHD_PR_SUCCESS:
240 0 : break;
241 : }
242 :
243 : {
244 : struct TALER_ReservePublicKeyP reserve_pub;
245 : struct TALER_FullPayto exchange_payto_url;
246 : enum GNUNET_GenericReturnValue ret;
247 : struct TALER_Amount amount;
248 : bool amount_missing;
249 : struct TALER_Amount *amount_ptr;
250 : struct GNUNET_JSON_Specification spec[] = {
251 0 : GNUNET_JSON_spec_fixed_auto ("reserve_pub",
252 : &reserve_pub),
253 0 : TALER_JSON_spec_full_payto_uri ("selected_exchange",
254 : &exchange_payto_url),
255 0 : GNUNET_JSON_spec_mark_optional (
256 : TALER_JSON_spec_amount ("amount",
257 0 : h->currency,
258 : &amount),
259 : &amount_missing),
260 0 : GNUNET_JSON_spec_end ()
261 : };
262 :
263 0 : if (GNUNET_OK !=
264 0 : (ret = TALER_MHD_parse_json_data (connection,
265 : json,
266 : spec)))
267 : {
268 0 : GNUNET_break_op (0);
269 0 : json_decref (json);
270 0 : return (GNUNET_NO == ret) ? MHD_YES : MHD_NO;
271 : }
272 :
273 0 : amount_ptr = amount_missing ? NULL : &amount;
274 :
275 0 : res = do_post_withdrawal (h,
276 : connection,
277 : wopid,
278 : &reserve_pub,
279 : exchange_payto_url,
280 : amount_ptr);
281 : }
282 0 : json_decref (json);
283 0 : return res;
284 : }
|