Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2017, 2021 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU Affero 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 Affero General Public License for more details.
12 :
13 : You should have received a copy of the GNU Affero General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file taler-exchange-httpd_deposits_get.c
18 : * @brief Handle wire deposit tracking-related requests
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <gnunet/gnunet_util_lib.h>
23 : #include <jansson.h>
24 : #include <microhttpd.h>
25 : #include <pthread.h>
26 : #include "taler_json_lib.h"
27 : #include "taler_mhd_lib.h"
28 : #include "taler_signatures.h"
29 : #include "taler-exchange-httpd_keys.h"
30 : #include "taler-exchange-httpd_deposits_get.h"
31 : #include "taler-exchange-httpd_responses.h"
32 :
33 :
34 : /**
35 : * Closure for #handle_wtid_data.
36 : */
37 : struct DepositWtidContext
38 : {
39 :
40 : /**
41 : * Hash over the proposal data of the contract for which this deposit is made.
42 : */
43 : struct TALER_PrivateContractHashP h_contract_terms;
44 :
45 : /**
46 : * Hash over the wiring information of the merchant.
47 : */
48 : struct TALER_MerchantWireHashP h_wire;
49 :
50 : /**
51 : * The Merchant's public key. The deposit inquiry request is to be
52 : * signed by the corresponding private key (using EdDSA).
53 : */
54 : struct TALER_MerchantPublicKeyP merchant;
55 :
56 : /**
57 : * The coin's public key. This is the value that must have been
58 : * signed (blindly) by the Exchange.
59 : */
60 : struct TALER_CoinSpendPublicKeyP coin_pub;
61 :
62 : /**
63 : * Set by #handle_wtid data to the wire transfer ID.
64 : */
65 : struct TALER_WireTransferIdentifierRawP wtid;
66 :
67 : /**
68 : * Set by #handle_wtid data to the coin's contribution to the wire transfer.
69 : */
70 : struct TALER_Amount coin_contribution;
71 :
72 : /**
73 : * Set by #handle_wtid data to the fee charged to the coin.
74 : */
75 : struct TALER_Amount coin_fee;
76 :
77 : /**
78 : * Set by #handle_wtid data to the wire transfer execution time.
79 : */
80 : struct GNUNET_TIME_Timestamp execution_time;
81 :
82 : /**
83 : * Set by #handle_wtid to the coin contribution to the transaction
84 : * (that is, @e coin_contribution minus @e coin_fee).
85 : */
86 : struct TALER_Amount coin_delta;
87 :
88 : /**
89 : * KYC status information for the receiving account.
90 : */
91 : struct TALER_EXCHANGEDB_KycStatus kyc;
92 :
93 : /**
94 : * Set to #GNUNET_YES by #handle_wtid if the wire transfer is still pending
95 : * (and the above were not set).
96 : * Set to #GNUNET_SYSERR if there was a serious error.
97 : */
98 : enum GNUNET_GenericReturnValue pending;
99 : };
100 :
101 :
102 : /**
103 : * A merchant asked for details about a deposit. Provide
104 : * them. Generates the 200 reply.
105 : *
106 : * @param connection connection to the client
107 : * @param ctx details to respond with
108 : * @return MHD result code
109 : */
110 : static MHD_RESULT
111 0 : reply_deposit_details (
112 : struct MHD_Connection *connection,
113 : const struct DepositWtidContext *ctx)
114 : {
115 : struct TALER_ExchangePublicKeyP pub;
116 : struct TALER_ExchangeSignatureP sig;
117 : enum TALER_ErrorCode ec;
118 :
119 0 : if (TALER_EC_NONE !=
120 0 : (ec = TALER_exchange_online_confirm_wire_sign (
121 : &TEH_keys_exchange_sign_,
122 : &ctx->h_wire,
123 : &ctx->h_contract_terms,
124 : &ctx->wtid,
125 : &ctx->coin_pub,
126 : ctx->execution_time,
127 : &ctx->coin_delta,
128 : &pub,
129 : &sig)))
130 : {
131 0 : return TALER_MHD_reply_with_ec (connection,
132 : ec,
133 : NULL);
134 : }
135 0 : return TALER_MHD_REPLY_JSON_PACK (
136 : connection,
137 : MHD_HTTP_OK,
138 : GNUNET_JSON_pack_data_auto ("wtid",
139 : &ctx->wtid),
140 : GNUNET_JSON_pack_timestamp ("execution_time",
141 : ctx->execution_time),
142 : TALER_JSON_pack_amount ("coin_contribution",
143 : &ctx->coin_delta),
144 : GNUNET_JSON_pack_data_auto ("exchange_sig",
145 : &sig),
146 : GNUNET_JSON_pack_data_auto ("exchange_pub",
147 : &pub));
148 : }
149 :
150 :
151 : /**
152 : * Execute a "deposits" GET. Returns the transfer information
153 : * associated with the given deposit.
154 : *
155 : * If it returns a non-error code, the transaction logic MUST
156 : * NOT queue a MHD response. IF it returns an hard error, the
157 : * transaction logic MUST queue a MHD response and set @a mhd_ret. IF
158 : * it returns the soft error code, the function MAY be called again to
159 : * retry and MUST NOT queue a MHD response.
160 : *
161 : * @param cls closure of type `struct DepositWtidContext *`
162 : * @param connection MHD request which triggered the transaction
163 : * @param[out] mhd_ret set to MHD response status for @a connection,
164 : * if transaction failed (!)
165 : * @return transaction status
166 : */
167 : static enum GNUNET_DB_QueryStatus
168 0 : deposits_get_transaction (void *cls,
169 : struct MHD_Connection *connection,
170 : MHD_RESULT *mhd_ret)
171 : {
172 0 : struct DepositWtidContext *ctx = cls;
173 : enum GNUNET_DB_QueryStatus qs;
174 : bool pending;
175 : struct TALER_Amount fee;
176 :
177 0 : qs = TEH_plugin->lookup_transfer_by_deposit (TEH_plugin->cls,
178 0 : &ctx->h_contract_terms,
179 0 : &ctx->h_wire,
180 0 : &ctx->coin_pub,
181 0 : &ctx->merchant,
182 : &pending,
183 : &ctx->wtid,
184 : &ctx->execution_time,
185 : &ctx->coin_contribution,
186 : &fee,
187 : &ctx->kyc);
188 0 : if (0 > qs)
189 : {
190 0 : if (GNUNET_DB_STATUS_HARD_ERROR == qs)
191 : {
192 0 : GNUNET_break (0);
193 0 : *mhd_ret = TALER_MHD_reply_with_error (connection,
194 : MHD_HTTP_INTERNAL_SERVER_ERROR,
195 : TALER_EC_GENERIC_DB_FETCH_FAILED,
196 : NULL);
197 : }
198 0 : return qs;
199 : }
200 0 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
201 : {
202 0 : *mhd_ret = TALER_MHD_reply_with_error (connection,
203 : MHD_HTTP_NOT_FOUND,
204 : TALER_EC_EXCHANGE_DEPOSITS_GET_NOT_FOUND,
205 : NULL);
206 0 : return GNUNET_DB_STATUS_HARD_ERROR;
207 : }
208 :
209 0 : if (0 >
210 0 : TALER_amount_subtract (&ctx->coin_delta,
211 0 : &ctx->coin_contribution,
212 : &fee))
213 : {
214 0 : GNUNET_break (0);
215 0 : ctx->pending = GNUNET_SYSERR;
216 0 : return qs;
217 : }
218 0 : ctx->pending = (pending) ? GNUNET_YES : GNUNET_NO;
219 0 : return qs;
220 : }
221 :
222 :
223 : /**
224 : * Lookup and return the wire transfer identifier.
225 : *
226 : * @param connection the MHD connection to handle
227 : * @param ctx context of the signed request to execute
228 : * @return MHD result code
229 : */
230 : static MHD_RESULT
231 0 : handle_track_transaction_request (
232 : struct MHD_Connection *connection,
233 : struct DepositWtidContext *ctx)
234 : {
235 : MHD_RESULT mhd_ret;
236 :
237 0 : if (GNUNET_OK !=
238 0 : TEH_DB_run_transaction (connection,
239 : "handle deposits GET",
240 : TEH_MT_REQUEST_OTHER,
241 : &mhd_ret,
242 : &deposits_get_transaction,
243 : ctx))
244 0 : return mhd_ret;
245 0 : if (GNUNET_SYSERR == ctx->pending)
246 0 : return TALER_MHD_reply_with_error (connection,
247 : MHD_HTTP_INTERNAL_SERVER_ERROR,
248 : TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
249 : "wire fees exceed aggregate in database");
250 0 : if (ctx->pending)
251 0 : return TALER_MHD_REPLY_JSON_PACK (
252 : connection,
253 : MHD_HTTP_ACCEPTED,
254 : GNUNET_JSON_pack_allow_null (
255 : (0 == ctx->kyc.requirement_row)
256 : ? GNUNET_JSON_pack_string ("requirement_row",
257 : NULL)
258 : : GNUNET_JSON_pack_uint64 ("requirement_row",
259 : ctx->kyc.requirement_row)),
260 : GNUNET_JSON_pack_bool ("kyc_ok",
261 : ctx->kyc.ok),
262 : GNUNET_JSON_pack_timestamp ("execution_time",
263 : ctx->execution_time));
264 0 : return reply_deposit_details (connection,
265 : ctx);
266 : }
267 :
268 :
269 : MHD_RESULT
270 0 : TEH_handler_deposits_get (struct TEH_RequestContext *rc,
271 : const char *const args[4])
272 : {
273 : enum GNUNET_GenericReturnValue res;
274 : struct TALER_MerchantSignatureP merchant_sig;
275 : struct DepositWtidContext ctx;
276 :
277 0 : if (GNUNET_OK !=
278 0 : GNUNET_STRINGS_string_to_data (args[0],
279 : strlen (args[0]),
280 : &ctx.h_wire,
281 : sizeof (ctx.h_wire)))
282 : {
283 0 : GNUNET_break_op (0);
284 0 : return TALER_MHD_reply_with_error (rc->connection,
285 : MHD_HTTP_BAD_REQUEST,
286 : TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_H_WIRE,
287 : args[0]);
288 : }
289 0 : if (GNUNET_OK !=
290 0 : GNUNET_STRINGS_string_to_data (args[1],
291 0 : strlen (args[1]),
292 : &ctx.merchant,
293 : sizeof (ctx.merchant)))
294 : {
295 0 : GNUNET_break_op (0);
296 0 : return TALER_MHD_reply_with_error (rc->connection,
297 : MHD_HTTP_BAD_REQUEST,
298 : TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_MERCHANT_PUB,
299 0 : args[1]);
300 : }
301 0 : if (GNUNET_OK !=
302 0 : GNUNET_STRINGS_string_to_data (args[2],
303 0 : strlen (args[2]),
304 : &ctx.h_contract_terms,
305 : sizeof (ctx.h_contract_terms)))
306 : {
307 0 : GNUNET_break_op (0);
308 0 : return TALER_MHD_reply_with_error (rc->connection,
309 : MHD_HTTP_BAD_REQUEST,
310 : TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_H_CONTRACT_TERMS,
311 0 : args[2]);
312 : }
313 0 : if (GNUNET_OK !=
314 0 : GNUNET_STRINGS_string_to_data (args[3],
315 0 : strlen (args[3]),
316 : &ctx.coin_pub,
317 : sizeof (ctx.coin_pub)))
318 : {
319 0 : GNUNET_break_op (0);
320 0 : return TALER_MHD_reply_with_error (rc->connection,
321 : MHD_HTTP_BAD_REQUEST,
322 : TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_COIN_PUB,
323 0 : args[3]);
324 : }
325 0 : res = TALER_MHD_parse_request_arg_data (rc->connection,
326 : "merchant_sig",
327 : &merchant_sig,
328 : sizeof (merchant_sig));
329 0 : if (GNUNET_SYSERR == res)
330 0 : return MHD_NO; /* internal error */
331 0 : if (GNUNET_NO == res)
332 0 : return MHD_YES; /* parse error */
333 0 : TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
334 : {
335 0 : if (GNUNET_OK !=
336 0 : TALER_merchant_deposit_verify (&ctx.merchant,
337 : &ctx.coin_pub,
338 : &ctx.h_contract_terms,
339 : &ctx.h_wire,
340 : &merchant_sig))
341 : {
342 0 : GNUNET_break_op (0);
343 0 : return TALER_MHD_reply_with_error (rc->connection,
344 : MHD_HTTP_FORBIDDEN,
345 : TALER_EC_EXCHANGE_DEPOSITS_GET_MERCHANT_SIGNATURE_INVALID,
346 : NULL);
347 : }
348 : }
349 :
350 0 : return handle_track_transaction_request (rc->connection,
351 : &ctx);
352 : }
353 :
354 :
355 : /* end of taler-exchange-httpd_deposits_get.c */
|