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