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 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 General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file taler-merchant-httpd_get-tips-ID.c
18 : * @brief implementation of GET /tips/$ID
19 : * @author Marcello Stanisci
20 : * @author Christian Grothoff
21 : */
22 : #include "platform.h"
23 : #include <jansson.h>
24 : #include <taler/taler_signatures.h>
25 : #include <taler/taler_json_lib.h>
26 : #include "taler-merchant-httpd_get-tips-ID.h"
27 : #include "taler-merchant-httpd_mhd.h"
28 : #include "taler-merchant-httpd_qr.h"
29 : #include "taler-merchant-httpd_templating.h"
30 :
31 : char *
32 0 : TMH_make_taler_tip_uri (struct MHD_Connection *con,
33 : const struct TALER_TipIdentifierP *tip_id,
34 : const char *instance_id)
35 : {
36 : const char *host;
37 : const char *forwarded_host;
38 : const char *uri_path;
39 0 : struct GNUNET_Buffer buf = { 0 };
40 :
41 0 : host = MHD_lookup_connection_value (con,
42 : MHD_HEADER_KIND,
43 : "Host");
44 0 : forwarded_host = MHD_lookup_connection_value (con,
45 : MHD_HEADER_KIND,
46 : "X-Forwarded-Host");
47 :
48 0 : uri_path = MHD_lookup_connection_value (con,
49 : MHD_HEADER_KIND,
50 : "X-Forwarded-Prefix");
51 0 : if (NULL != forwarded_host)
52 0 : host = forwarded_host;
53 :
54 0 : if (NULL == host)
55 : {
56 0 : GNUNET_break (0);
57 0 : return NULL;
58 : }
59 :
60 0 : GNUNET_assert (NULL != instance_id);
61 0 : GNUNET_assert (NULL != tip_id);
62 :
63 0 : GNUNET_buffer_write_str (&buf,
64 : "taler");
65 0 : if (GNUNET_NO == TALER_mhd_is_https (con))
66 0 : GNUNET_buffer_write_str (&buf,
67 : "+http");
68 0 : GNUNET_buffer_write_str (&buf,
69 : "://tip/");
70 0 : GNUNET_buffer_write_str (&buf,
71 : host);
72 0 : if (NULL != uri_path)
73 0 : GNUNET_buffer_write_path (&buf,
74 : uri_path);
75 0 : if (0 != strcmp ("default",
76 : instance_id))
77 : {
78 0 : GNUNET_buffer_write_path (&buf,
79 : "instances");
80 0 : GNUNET_buffer_write_path (&buf,
81 : instance_id);
82 : }
83 : /* Ensure previous part is slash-terminated */
84 0 : GNUNET_buffer_write_path (&buf,
85 : "");
86 0 : GNUNET_buffer_write_data_encoded (&buf,
87 : tip_id,
88 : sizeof (*tip_id));
89 0 : return GNUNET_buffer_reap_str (&buf);
90 : }
91 :
92 :
93 : char *
94 0 : TMH_make_tip_status_url (struct MHD_Connection *con,
95 : const struct TALER_TipIdentifierP *tip_id,
96 : const char *instance_id)
97 : {
98 : const char *host;
99 : const char *forwarded_host;
100 : const char *uri_path;
101 0 : struct GNUNET_Buffer buf = { 0 };
102 :
103 0 : host = MHD_lookup_connection_value (con,
104 : MHD_HEADER_KIND,
105 : "Host");
106 0 : forwarded_host = MHD_lookup_connection_value (con,
107 : MHD_HEADER_KIND,
108 : "X-Forwarded-Host");
109 :
110 0 : uri_path = MHD_lookup_connection_value (con,
111 : MHD_HEADER_KIND,
112 : "X-Forwarded-Prefix");
113 0 : if (NULL != forwarded_host)
114 0 : host = forwarded_host;
115 :
116 0 : if (NULL == host)
117 : {
118 0 : GNUNET_break (0);
119 0 : return NULL;
120 : }
121 :
122 0 : GNUNET_assert (NULL != instance_id);
123 0 : GNUNET_assert (NULL != tip_id);
124 :
125 0 : if (GNUNET_NO == TALER_mhd_is_https (con))
126 0 : GNUNET_buffer_write_str (&buf,
127 : "http://");
128 : else
129 0 : GNUNET_buffer_write_str (&buf,
130 : "https://");
131 0 : GNUNET_buffer_write_str (&buf,
132 : host);
133 0 : if (NULL != uri_path)
134 0 : GNUNET_buffer_write_path (&buf,
135 : uri_path);
136 0 : if (0 != strcmp ("default",
137 : instance_id))
138 : {
139 0 : GNUNET_buffer_write_path (&buf,
140 : "instances");
141 0 : GNUNET_buffer_write_path (&buf,
142 : instance_id);
143 : }
144 0 : GNUNET_buffer_write_path (&buf,
145 : "tips/");
146 0 : GNUNET_buffer_write_data_encoded (&buf,
147 : tip_id,
148 : sizeof (*tip_id));
149 0 : return GNUNET_buffer_reap_str (&buf);
150 : }
151 :
152 :
153 : MHD_RESULT
154 0 : TMH_get_tips_ID (const struct TMH_RequestHandler *rh,
155 : struct MHD_Connection *connection,
156 : struct TMH_HandlerContext *hc)
157 : {
158 : struct TALER_TipIdentifierP tip_id;
159 : enum GNUNET_DB_QueryStatus qs;
160 : struct TALER_Amount total_authorized;
161 : struct TALER_Amount total_picked_up;
162 : struct GNUNET_TIME_Timestamp expiration;
163 : char *exchange_url;
164 : struct TALER_ReservePrivateKeyP reserve_priv;
165 :
166 0 : if (GNUNET_OK !=
167 0 : GNUNET_CRYPTO_hash_from_string (hc->infix,
168 : &tip_id.hash))
169 : {
170 : /* tip_id has wrong encoding */
171 0 : GNUNET_break_op (0);
172 0 : return TALER_MHD_reply_with_error (connection,
173 : MHD_HTTP_BAD_REQUEST,
174 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
175 0 : hc->infix);
176 : }
177 :
178 0 : TMH_db->preflight (TMH_db->cls);
179 0 : qs = TMH_db->lookup_tip (TMH_db->cls,
180 0 : hc->instance->settings.id,
181 : &tip_id,
182 : &total_authorized,
183 : &total_picked_up,
184 : &expiration,
185 : &exchange_url,
186 : &reserve_priv);
187 0 : if (0 > qs)
188 : {
189 : /* single, read-only SQL statements should never cause
190 : serialization problems */
191 0 : GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
192 : /* Always report on hard error as well to enable diagnostics */
193 0 : GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
194 0 : return TALER_MHD_reply_with_error (connection,
195 : MHD_HTTP_INTERNAL_SERVER_ERROR,
196 : TALER_EC_GENERIC_DB_FETCH_FAILED,
197 : NULL);
198 : }
199 0 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
200 : {
201 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
202 : "Unknown tip id given: `%s'\n",
203 : hc->infix);
204 0 : return TALER_MHD_reply_with_error (connection,
205 : MHD_HTTP_NOT_FOUND,
206 : TALER_EC_MERCHANT_GENERIC_TIP_ID_UNKNOWN,
207 0 : hc->infix);
208 : }
209 :
210 : /* Build response */
211 : {
212 : struct TALER_Amount remaining;
213 : MHD_RESULT ret;
214 :
215 0 : GNUNET_break (0 <=
216 : TALER_amount_subtract (&remaining,
217 : &total_authorized,
218 : &total_picked_up));
219 0 : if (TMH_MHD_test_html_desired (connection))
220 : {
221 : char *qr;
222 : char *uri;
223 : char *tip_status_url;
224 :
225 0 : uri = TMH_make_taler_tip_uri (connection,
226 : &tip_id,
227 0 : hc->instance->settings.id);
228 0 : tip_status_url = TMH_make_tip_status_url (connection,
229 : &tip_id,
230 0 : hc->instance->settings.id);
231 0 : qr = TMH_create_qrcode (uri);
232 0 : if (NULL == qr)
233 : {
234 0 : GNUNET_break (0);
235 0 : GNUNET_free (uri);
236 0 : ret = TALER_MHD_reply_with_error (connection,
237 : MHD_HTTP_INTERNAL_SERVER_ERROR,
238 : TALER_EC_GENERIC_ALLOCATION_FAILURE,
239 : "during QR code generation");
240 : }
241 : else
242 : {
243 : json_t *context;
244 :
245 0 : context = GNUNET_JSON_PACK (
246 : TALER_JSON_pack_amount ("remaining_tip",
247 : &remaining),
248 : GNUNET_JSON_pack_string ("taler_tip_uri",
249 : uri),
250 : GNUNET_JSON_pack_string ("taler_tip_qrcode_svg",
251 : qr));
252 0 : ret = TMH_return_from_template (connection,
253 0 : ( (0 == remaining.value) &&
254 0 : (0 == remaining.fraction) )
255 : ? MHD_HTTP_GONE
256 : : MHD_HTTP_OK,
257 0 : ( (0 == remaining.value) &&
258 0 : (0 == remaining.fraction) )
259 : ? "depleted_tip"
260 : : "offer_tip",
261 0 : hc->instance->settings.id,
262 : uri,
263 : context);
264 0 : json_decref (context);
265 : }
266 0 : GNUNET_free (tip_status_url);
267 0 : GNUNET_free (uri);
268 0 : GNUNET_free (qr);
269 : }
270 : else
271 : {
272 0 : ret = TALER_MHD_REPLY_JSON_PACK (
273 : connection,
274 : TALER_amount_is_zero (&remaining)
275 : ? MHD_HTTP_GONE
276 : : MHD_HTTP_OK,
277 : GNUNET_JSON_pack_string ("exchange_url",
278 : exchange_url),
279 : TALER_JSON_pack_amount ("tip_amount",
280 : &remaining),
281 : GNUNET_JSON_pack_timestamp ("expiration",
282 : expiration));
283 : }
284 0 : GNUNET_free (exchange_url);
285 0 : return ret;
286 : }
287 : }
288 :
289 :
290 : /* end of taler-merchant-httpd_get-tips-ID.c */
|