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