Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 2014-2021 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_post-orders-ID-paid.h"
31 :
32 :
33 : /**
34 : * Use database to notify other clients about the
35 : * session being captured.
36 : *
37 : * @param hc http context
38 : * @param session_id the captured session
39 : * @param fulfillment_url the URL that is now paid for by @a session_id
40 : */
41 : static void
42 0 : trigger_session_notification (struct TMH_HandlerContext *hc,
43 : const char *session_id,
44 : const char *fulfillment_url)
45 : {
46 0 : struct TMH_SessionEventP session_eh = {
47 0 : .header.size = htons (sizeof (session_eh)),
48 0 : .header.type = htons (TALER_DBEVENT_MERCHANT_SESSION_CAPTURED),
49 0 : .merchant_pub = hc->instance->merchant_pub
50 : };
51 :
52 0 : GNUNET_CRYPTO_hash (session_id,
53 : strlen (session_id),
54 : &session_eh.h_session_id);
55 0 : GNUNET_CRYPTO_hash (fulfillment_url,
56 : strlen (fulfillment_url),
57 : &session_eh.h_fulfillment_url);
58 0 : TMH_db->event_notify (TMH_db->cls,
59 : &session_eh.header,
60 : NULL,
61 : 0);
62 0 : }
63 :
64 :
65 : MHD_RESULT
66 0 : TMH_post_orders_ID_paid (const struct TMH_RequestHandler *rh,
67 : struct MHD_Connection *connection,
68 : struct TMH_HandlerContext *hc)
69 : {
70 0 : const char *order_id = hc->infix;
71 : struct TALER_MerchantSignatureP merchant_sig;
72 : const char *session_id;
73 : struct TALER_PrivateContractHashP hct;
74 : json_t *contract_terms;
75 : const char *fulfillment_url;
76 : enum GNUNET_DB_QueryStatus qs;
77 :
78 : {
79 : struct GNUNET_JSON_Specification spec[] = {
80 0 : GNUNET_JSON_spec_fixed_auto ("sig",
81 : &merchant_sig),
82 0 : GNUNET_JSON_spec_fixed_auto ("h_contract",
83 : &hct),
84 0 : GNUNET_JSON_spec_string ("session_id",
85 : &session_id),
86 0 : GNUNET_JSON_spec_end ()
87 : };
88 : enum GNUNET_GenericReturnValue res;
89 :
90 0 : res = TALER_MHD_parse_json_data (connection,
91 0 : hc->request_body,
92 : spec);
93 0 : if (GNUNET_YES != res)
94 : {
95 0 : GNUNET_break_op (0);
96 : return (GNUNET_NO == res)
97 : ? MHD_YES
98 0 : : MHD_NO;
99 : }
100 : }
101 :
102 :
103 0 : if (GNUNET_OK !=
104 0 : TALER_merchant_pay_verify (&hct,
105 0 : &hc->instance->merchant_pub,
106 : &merchant_sig))
107 : {
108 0 : GNUNET_break_op (0);
109 0 : return TALER_MHD_reply_with_error (connection,
110 : MHD_HTTP_FORBIDDEN,
111 : TALER_EC_MERCHANT_POST_ORDERS_ID_PAID_COIN_SIGNATURE_INVALID,
112 : NULL);
113 : }
114 :
115 0 : TMH_db->preflight (TMH_db->cls);
116 : {
117 : uint64_t order_serial;
118 : bool paid;
119 :
120 0 : qs = TMH_db->lookup_contract_terms (TMH_db->cls,
121 0 : hc->instance->settings.id,
122 : order_id,
123 : &contract_terms,
124 : &order_serial,
125 : &paid,
126 : NULL);
127 : }
128 0 : if (0 > qs)
129 : {
130 : /* single, read-only SQL statements should never cause
131 : serialization problems */
132 0 : GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
133 : /* Always report on hard error as well to enable diagnostics */
134 0 : GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
135 0 : return TALER_MHD_reply_with_error (connection,
136 : MHD_HTTP_INTERNAL_SERVER_ERROR,
137 : TALER_EC_GENERIC_DB_FETCH_FAILED,
138 : "lookup_contract_terms");
139 : }
140 0 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
141 : {
142 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
143 : "Unknown order id given: `%s'\n",
144 : order_id);
145 0 : return TALER_MHD_reply_with_error (connection,
146 : MHD_HTTP_NOT_FOUND,
147 : TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN,
148 : order_id);
149 : }
150 :
151 : {
152 : struct TALER_PrivateContractHashP h_contract_terms;
153 :
154 0 : if (GNUNET_OK !=
155 0 : TALER_JSON_contract_hash (contract_terms,
156 : &h_contract_terms))
157 : {
158 0 : GNUNET_break (0);
159 0 : json_decref (contract_terms);
160 0 : return TALER_MHD_reply_with_error (connection,
161 : MHD_HTTP_INTERNAL_SERVER_ERROR,
162 : TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
163 : NULL);
164 : }
165 0 : if (0 != GNUNET_memcmp (&hct,
166 : &h_contract_terms))
167 : {
168 0 : json_decref (contract_terms);
169 0 : return TALER_MHD_reply_with_error (connection,
170 : MHD_HTTP_BAD_REQUEST,
171 : TALER_EC_MERCHANT_POST_ORDERS_ID_PAID_CONTRACT_HASH_MISMATCH,
172 : NULL);
173 : }
174 : }
175 :
176 :
177 : fulfillment_url
178 0 : = json_string_value (json_object_get (contract_terms,
179 : "fulfillment_url"));
180 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
181 : "Marking contract %s with %s/%s as paid\n",
182 : order_id,
183 : session_id,
184 : fulfillment_url);
185 0 : qs = TMH_db->mark_contract_paid (TMH_db->cls,
186 0 : hc->instance->settings.id,
187 : &hct,
188 : session_id);
189 : /* If the order was paid already, we get qs == 0. */
190 0 : if (0 > qs)
191 : {
192 0 : GNUNET_break (0);
193 0 : json_decref (contract_terms);
194 0 : return TALER_MHD_reply_with_error (connection,
195 : MHD_HTTP_INTERNAL_SERVER_ERROR,
196 : TALER_EC_GENERIC_DB_STORE_FAILED,
197 : "mark_contract_paid");
198 : }
199 :
200 : /* Wake everybody up who waits for this fulfillment_url and session_id */
201 0 : if ( (NULL != fulfillment_url) &&
202 0 : (NULL != session_id) )
203 0 : trigger_session_notification (hc,
204 : session_id,
205 : fulfillment_url);
206 : /* fulfillment_url is part of the contract_terms */
207 0 : json_decref (contract_terms);
208 0 : return TALER_MHD_reply_static (connection,
209 : MHD_HTTP_NO_CONTENT,
210 : NULL,
211 : NULL,
212 : 0);
213 : }
214 :
215 :
216 : /* end of taler-merchant-httpd_post-orders-ID-paid.c */
|