Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2015--2024 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU 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
15 : <http://www.gnu.org/licenses/>
16 : */
17 : /**
18 : * @file bank-lib/bank_api_admin_add_incoming.c
19 : * @brief Implementation of the /admin/add-incoming requests of the bank's HTTP API
20 : * @author Christian Grothoff
21 : */
22 : #include "bank_api_common.h"
23 : #include <microhttpd.h> /* just for HTTP status codes */
24 : #include "taler/taler_signatures.h"
25 : #include "taler/taler_curl_lib.h"
26 :
27 :
28 : /**
29 : * @brief An /admin/add-incoming Handle
30 : */
31 : struct TALER_BANK_AdminAddIncomingHandle
32 : {
33 :
34 : /**
35 : * The url for this request.
36 : */
37 : char *request_url;
38 :
39 : /**
40 : * POST context.
41 : */
42 : struct TALER_CURL_PostContext post_ctx;
43 :
44 : /**
45 : * Handle for the request.
46 : */
47 : struct GNUNET_CURL_Job *job;
48 :
49 : /**
50 : * Function to call with the result.
51 : */
52 : TALER_BANK_AdminAddIncomingCallback cb;
53 :
54 : /**
55 : * Closure for @a cb.
56 : */
57 : void *cb_cls;
58 :
59 : };
60 :
61 :
62 : /**
63 : * Function called when we're done processing the
64 : * HTTP /admin/add-incoming request.
65 : *
66 : * @param cls the `struct TALER_BANK_AdminAddIncomingHandle`
67 : * @param response_code HTTP response code, 0 on error
68 : * @param response parsed JSON result, NULL on error
69 : */
70 : static void
71 61 : handle_admin_add_incoming_finished (void *cls,
72 : long response_code,
73 : const void *response)
74 : {
75 61 : struct TALER_BANK_AdminAddIncomingHandle *aai = cls;
76 61 : const json_t *j = response;
77 61 : struct TALER_BANK_AdminAddIncomingResponse ir = {
78 : .http_status = response_code,
79 : .response = response
80 : };
81 :
82 61 : aai->job = NULL;
83 61 : switch (response_code)
84 : {
85 0 : case 0:
86 0 : ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
87 0 : break;
88 59 : case MHD_HTTP_OK:
89 : {
90 : struct GNUNET_JSON_Specification spec[] = {
91 59 : GNUNET_JSON_spec_uint64 ("row_id",
92 : &ir.details.ok.serial_id),
93 59 : GNUNET_JSON_spec_timestamp ("timestamp",
94 : &ir.details.ok.timestamp),
95 59 : GNUNET_JSON_spec_end ()
96 : };
97 :
98 59 : if (GNUNET_OK !=
99 59 : GNUNET_JSON_parse (j,
100 : spec,
101 : NULL, NULL))
102 : {
103 0 : GNUNET_break_op (0);
104 0 : ir.http_status = 0;
105 0 : ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
106 0 : break;
107 : }
108 : }
109 59 : break;
110 0 : case MHD_HTTP_BAD_REQUEST:
111 : /* This should never happen, either us or the bank is buggy
112 : (or API version conflict); just pass JSON reply to the application */
113 0 : GNUNET_break_op (0);
114 0 : ir.ec = TALER_JSON_get_error_code (j);
115 0 : break;
116 0 : case MHD_HTTP_FORBIDDEN:
117 : /* Access denied */
118 0 : ir.ec = TALER_JSON_get_error_code (j);
119 0 : break;
120 0 : case MHD_HTTP_UNAUTHORIZED:
121 : /* Nothing really to verify, bank says the password is invalid; we should
122 : pass the JSON reply to the application */
123 0 : ir.ec = TALER_JSON_get_error_code (j);
124 0 : break;
125 0 : case MHD_HTTP_NOT_FOUND:
126 : /* Nothing really to verify, maybe account really does not exist.
127 : We should pass the JSON reply to the application */
128 0 : ir.ec = TALER_JSON_get_error_code (j);
129 0 : break;
130 2 : case MHD_HTTP_CONFLICT:
131 : /* Nothing to verify, we used the same wire subject
132 : twice? */
133 2 : ir.ec = TALER_JSON_get_error_code (j);
134 2 : break;
135 0 : case MHD_HTTP_INTERNAL_SERVER_ERROR:
136 : /* Server had an internal issue; we should retry, but this API
137 : leaves this to the application */
138 0 : ir.ec = TALER_JSON_get_error_code (j);
139 0 : break;
140 0 : default:
141 : /* unexpected response code */
142 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
143 : "Unexpected response code %u\n",
144 : (unsigned int) response_code);
145 0 : GNUNET_break (0);
146 0 : ir.ec = TALER_JSON_get_error_code (j);
147 0 : break;
148 : }
149 61 : aai->cb (aai->cb_cls,
150 : &ir);
151 61 : TALER_BANK_admin_add_incoming_cancel (aai);
152 61 : }
153 :
154 :
155 : struct TALER_BANK_AdminAddIncomingHandle *
156 61 : TALER_BANK_admin_add_incoming (
157 : struct GNUNET_CURL_Context *ctx,
158 : const struct TALER_BANK_AuthenticationData *auth,
159 : const struct TALER_ReservePublicKeyP *reserve_pub,
160 : const struct TALER_Amount *amount,
161 : const struct TALER_FullPayto debit_account,
162 : TALER_BANK_AdminAddIncomingCallback res_cb,
163 : void *res_cb_cls)
164 : {
165 : struct TALER_BANK_AdminAddIncomingHandle *aai;
166 : json_t *admin_obj;
167 : CURL *eh;
168 :
169 61 : if (NULL == debit_account.full_payto)
170 : {
171 0 : GNUNET_break (0);
172 0 : return NULL;
173 : }
174 61 : if (NULL == reserve_pub)
175 : {
176 0 : GNUNET_break (0);
177 0 : return NULL;
178 : }
179 61 : if (NULL == amount)
180 : {
181 0 : GNUNET_break (0);
182 0 : return NULL;
183 : }
184 61 : admin_obj = GNUNET_JSON_PACK (
185 : GNUNET_JSON_pack_data_auto ("reserve_pub",
186 : reserve_pub),
187 : TALER_JSON_pack_amount ("amount",
188 : amount),
189 : TALER_JSON_pack_full_payto ("debit_account",
190 : debit_account));
191 61 : if (NULL == admin_obj)
192 : {
193 0 : GNUNET_break (0);
194 0 : return NULL;
195 : }
196 61 : aai = GNUNET_new (struct TALER_BANK_AdminAddIncomingHandle);
197 61 : aai->cb = res_cb;
198 61 : aai->cb_cls = res_cb_cls;
199 61 : aai->request_url = TALER_url_join (auth->wire_gateway_url,
200 : "admin/add-incoming",
201 : NULL);
202 61 : if (NULL == aai->request_url)
203 : {
204 0 : GNUNET_free (aai);
205 0 : json_decref (admin_obj);
206 0 : return NULL;
207 : }
208 61 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
209 : "Requesting administrative transaction at `%s' for reserve %s\n",
210 : aai->request_url,
211 : TALER_B2S (reserve_pub));
212 : aai->post_ctx.headers
213 61 : = curl_slist_append (
214 : aai->post_ctx.headers,
215 : "Content-Type: application/json");
216 :
217 61 : eh = curl_easy_init ();
218 122 : if ( (NULL == eh) ||
219 : (GNUNET_OK !=
220 61 : TALER_BANK_setup_auth_ (eh,
221 61 : auth)) ||
222 : (CURLE_OK !=
223 61 : curl_easy_setopt (eh,
224 : CURLOPT_URL,
225 61 : aai->request_url)) ||
226 : (GNUNET_OK !=
227 61 : TALER_curl_easy_post (&aai->post_ctx,
228 : eh,
229 : admin_obj)) )
230 : {
231 0 : GNUNET_break (0);
232 0 : TALER_BANK_admin_add_incoming_cancel (aai);
233 0 : if (NULL != eh)
234 0 : curl_easy_cleanup (eh);
235 0 : json_decref (admin_obj);
236 0 : return NULL;
237 : }
238 61 : json_decref (admin_obj);
239 :
240 122 : aai->job = GNUNET_CURL_job_add2 (ctx,
241 : eh,
242 61 : aai->post_ctx.headers,
243 : &handle_admin_add_incoming_finished,
244 : aai);
245 61 : return aai;
246 : }
247 :
248 :
249 : void
250 61 : TALER_BANK_admin_add_incoming_cancel (
251 : struct TALER_BANK_AdminAddIncomingHandle *aai)
252 : {
253 61 : if (NULL != aai->job)
254 : {
255 0 : GNUNET_CURL_job_cancel (aai->job);
256 0 : aai->job = NULL;
257 : }
258 61 : TALER_curl_easy_post_finished (&aai->post_ctx);
259 61 : GNUNET_free (aai->request_url);
260 61 : GNUNET_free (aai);
261 61 : }
262 :
263 :
264 : /* end of bank_api_admin_add_incoming.c */
|