Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 2014-2023 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU Affero General Public License as
7 : 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, but
11 : 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 : /**
21 : * @file taler-merchant-httpd_post-orders-ID-paid.c
22 : * @brief handling of POST /orders/$ID/paid requests
23 : * @author Christian Grothoff
24 : */
25 : #include "platform.h"
26 : #include <taler/taler_dbevents.h>
27 : #include <taler/taler_signatures.h>
28 : #include <taler/taler_json_lib.h>
29 : #include <taler/taler_exchange_service.h>
30 : #include "taler-merchant-httpd_helper.h"
31 : #include "taler-merchant-httpd_post-orders-ID-paid.h"
32 :
33 :
34 : /**
35 : * Function called with information about a refund.
36 : * Sets the boolean in @a cls to true when called.
37 : *
38 : * @param cls closure, a `bool *`
39 : * @param coin_pub public coin from which the refund comes from
40 : * @param refund_amount refund amount which is being taken from @a coin_pub
41 : */
42 : static void
43 0 : refund_cb (
44 : void *cls,
45 : const struct TALER_CoinSpendPublicKeyP *coin_pub,
46 : const struct TALER_Amount *refund_amount)
47 : {
48 0 : bool *refunded = cls;
49 :
50 0 : *refunded = true;
51 0 : }
52 :
53 :
54 : /**
55 : * Use database to notify other clients about the
56 : * session being captured.
57 : *
58 : * @param hc http context
59 : * @param session_id the captured session
60 : * @param fulfillment_url the URL that is now paid for by @a session_id
61 : */
62 : static void
63 4 : trigger_session_notification (struct TMH_HandlerContext *hc,
64 : const char *session_id,
65 : const char *fulfillment_url)
66 : {
67 4 : struct TMH_SessionEventP session_eh = {
68 4 : .header.size = htons (sizeof (session_eh)),
69 4 : .header.type = htons (TALER_DBEVENT_MERCHANT_SESSION_CAPTURED),
70 4 : .merchant_pub = hc->instance->merchant_pub
71 : };
72 :
73 4 : GNUNET_CRYPTO_hash (session_id,
74 : strlen (session_id),
75 : &session_eh.h_session_id);
76 4 : GNUNET_CRYPTO_hash (fulfillment_url,
77 : strlen (fulfillment_url),
78 : &session_eh.h_fulfillment_url);
79 4 : TMH_db->event_notify (TMH_db->cls,
80 : &session_eh.header,
81 : NULL,
82 : 0);
83 4 : }
84 :
85 :
86 : MHD_RESULT
87 4 : TMH_post_orders_ID_paid (const struct TMH_RequestHandler *rh,
88 : struct MHD_Connection *connection,
89 : struct TMH_HandlerContext *hc)
90 : {
91 4 : const char *order_id = hc->infix;
92 : struct TALER_MerchantSignatureP merchant_sig;
93 : const char *session_id;
94 : int16_t choice_index;
95 : struct TALER_PrivateContractHashP hct;
96 : json_t *contract_terms;
97 : const char *fulfillment_url;
98 : enum GNUNET_DB_QueryStatus qs;
99 :
100 : {
101 : struct GNUNET_JSON_Specification spec[] = {
102 4 : GNUNET_JSON_spec_fixed_auto ("sig",
103 : &merchant_sig),
104 4 : GNUNET_JSON_spec_fixed_auto ("h_contract",
105 : &hct),
106 4 : GNUNET_JSON_spec_string ("session_id",
107 : &session_id),
108 4 : GNUNET_JSON_spec_mark_optional (
109 : GNUNET_JSON_spec_int16 ("choice_index",
110 : &choice_index),
111 : NULL),
112 4 : GNUNET_JSON_spec_end ()
113 : };
114 : enum GNUNET_GenericReturnValue res;
115 :
116 4 : choice_index = -1;
117 4 : res = TALER_MHD_parse_json_data (connection,
118 4 : hc->request_body,
119 : spec);
120 4 : if (GNUNET_YES != res)
121 : {
122 0 : GNUNET_break_op (0);
123 : return (GNUNET_NO == res)
124 : ? MHD_YES
125 0 : : MHD_NO;
126 : }
127 : }
128 :
129 4 : if (GNUNET_OK !=
130 4 : TALER_merchant_pay_verify (&hct,
131 4 : &hc->instance->merchant_pub,
132 : &merchant_sig))
133 : {
134 0 : GNUNET_break_op (0);
135 0 : return TALER_MHD_reply_with_error (connection,
136 : MHD_HTTP_FORBIDDEN,
137 : TALER_EC_MERCHANT_POST_ORDERS_ID_PAID_COIN_SIGNATURE_INVALID,
138 : NULL);
139 : }
140 :
141 4 : TMH_db->preflight (TMH_db->cls);
142 : {
143 : uint64_t order_serial;
144 :
145 4 : qs = TMH_db->lookup_contract_terms (TMH_db->cls,
146 4 : hc->instance->settings.id,
147 : order_id,
148 : &contract_terms,
149 : &order_serial,
150 : NULL);
151 : }
152 4 : if (0 > qs)
153 : {
154 : /* single, read-only SQL statements should never cause
155 : serialization problems */
156 0 : GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
157 : /* Always report on hard error as well to enable diagnostics */
158 0 : GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
159 0 : return TALER_MHD_reply_with_error (connection,
160 : MHD_HTTP_INTERNAL_SERVER_ERROR,
161 : TALER_EC_GENERIC_DB_FETCH_FAILED,
162 : "lookup_contract_terms");
163 : }
164 4 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
165 : {
166 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
167 : "Unknown order id given: `%s'\n",
168 : order_id);
169 0 : return TALER_MHD_reply_with_error (connection,
170 : MHD_HTTP_NOT_FOUND,
171 : TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN,
172 : order_id);
173 : }
174 :
175 : {
176 : struct TALER_PrivateContractHashP h_contract_terms;
177 :
178 4 : if (GNUNET_OK !=
179 4 : TALER_JSON_contract_hash (contract_terms,
180 : &h_contract_terms))
181 : {
182 0 : GNUNET_break (0);
183 0 : json_decref (contract_terms);
184 0 : return TALER_MHD_reply_with_error (connection,
185 : MHD_HTTP_INTERNAL_SERVER_ERROR,
186 : TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
187 : NULL);
188 : }
189 4 : if (0 != GNUNET_memcmp (&hct,
190 : &h_contract_terms))
191 : {
192 0 : json_decref (contract_terms);
193 0 : return TALER_MHD_reply_with_error (connection,
194 : MHD_HTTP_BAD_REQUEST,
195 : TALER_EC_MERCHANT_POST_ORDERS_ID_PAID_CONTRACT_HASH_MISMATCH,
196 : NULL);
197 : }
198 : }
199 :
200 : fulfillment_url
201 4 : = json_string_value (json_object_get (contract_terms,
202 : "fulfillment_url"));
203 4 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
204 : "Marking contract %s with %s/%s as paid\n",
205 : order_id,
206 : session_id,
207 : fulfillment_url);
208 4 : qs = TMH_db->mark_contract_paid (TMH_db->cls,
209 4 : hc->instance->settings.id,
210 : &hct,
211 : session_id,
212 : choice_index);
213 : /* If the order was paid already, we get qs == 0. */
214 4 : if (0 > qs)
215 : {
216 0 : GNUNET_break (0);
217 0 : json_decref (contract_terms);
218 0 : return TALER_MHD_reply_with_error (connection,
219 : MHD_HTTP_INTERNAL_SERVER_ERROR,
220 : TALER_EC_GENERIC_DB_STORE_FAILED,
221 : "mark_contract_paid");
222 : }
223 :
224 : /* Wake everybody up who waits for this fulfillment_url and session_id */
225 4 : if ( (NULL != fulfillment_url) &&
226 4 : (NULL != session_id) )
227 4 : trigger_session_notification (hc,
228 : session_id,
229 : fulfillment_url);
230 :
231 : /*Trigger webhook */
232 : /*Commented out until its purpose is defined
233 : {
234 : enum GNUNET_DB_QueryStatus qs;
235 : json_t *jhook;
236 :
237 : jhook = GNUNET_JSON_PACK (
238 : GNUNET_JSON_pack_object_incref ("contract_terms",
239 : contract_terms),
240 : GNUNET_JSON_pack_string ("order_id",
241 : order_id)
242 : );
243 : GNUNET_assert (NULL != jhook);
244 : qs = TMH_trigger_webhook (hc->instance->settings.id,
245 : "paid",
246 : jhook);
247 : json_decref (jhook);
248 : if (qs < 0)
249 : {
250 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
251 : "Failed to init the webhook for contract %s with %s/%s as paid\n",
252 : order_id,
253 : session_id,
254 : fulfillment_url);
255 : }
256 : }*/
257 :
258 : /* fulfillment_url is part of the contract_terms */
259 : {
260 4 : bool refunded = false;
261 :
262 4 : qs = TMH_db->lookup_refunds (TMH_db->cls,
263 4 : hc->instance->settings.id,
264 : &hct,
265 : &refund_cb,
266 : &refunded);
267 4 : json_decref (contract_terms);
268 4 : return TALER_MHD_REPLY_JSON_PACK (
269 : connection,
270 : MHD_HTTP_OK,
271 : GNUNET_JSON_pack_bool ("refunded",
272 : refunded));
273 : }
274 : }
275 :
276 :
277 : /* end of taler-merchant-httpd_post-orders-ID-paid.c */
|