Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2020 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 Affero General Public License for more details.
12 :
13 : You should have received a copy of the GNU Affero General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file taler-exchange-httpd_management_wire_enable.c
18 : * @brief Handle request to add wire account.
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <gnunet/gnunet_util_lib.h>
23 : #include <gnunet/gnunet_json_lib.h>
24 : #include <jansson.h>
25 : #include <microhttpd.h>
26 : #include <pthread.h>
27 : #include "taler_json_lib.h"
28 : #include "taler_mhd_lib.h"
29 : #include "taler_signatures.h"
30 : #include "taler-exchange-httpd_management.h"
31 : #include "taler-exchange-httpd_responses.h"
32 : #include "taler-exchange-httpd_wire.h"
33 :
34 :
35 : /**
36 : * Closure for the #add_wire transaction.
37 : */
38 : struct AddWireContext
39 : {
40 : /**
41 : * Master signature affirming the WIRE ADD operation
42 : * (includes timestamp).
43 : */
44 : struct TALER_MasterSignatureP master_sig_add;
45 :
46 : /**
47 : * Master signature to share with clients affirming the
48 : * wire details of the bank.
49 : */
50 : struct TALER_MasterSignatureP master_sig_wire;
51 :
52 : /**
53 : * Payto:// URI this is about.
54 : */
55 : const char *payto_uri;
56 :
57 : /**
58 : * Timestamp for checking against replay attacks.
59 : */
60 : struct GNUNET_TIME_Timestamp validity_start;
61 :
62 : };
63 :
64 :
65 : /**
66 : * Function implementing database transaction to add an wire. Runs the
67 : * transaction logic; IF it returns a non-error code, the transaction logic
68 : * MUST NOT queue a MHD response. IF it returns an hard error, the
69 : * transaction logic MUST queue a MHD response and set @a mhd_ret. IF it
70 : * returns the soft error code, the function MAY be called again to retry and
71 : * MUST not queue a MHD response.
72 : *
73 : * @param cls closure with a `struct AddWireContext`
74 : * @param connection MHD request which triggered the transaction
75 : * @param[out] mhd_ret set to MHD response status for @a connection,
76 : * if transaction failed (!)
77 : * @return transaction status
78 : */
79 : static enum GNUNET_DB_QueryStatus
80 0 : add_wire (void *cls,
81 : struct MHD_Connection *connection,
82 : MHD_RESULT *mhd_ret)
83 : {
84 0 : struct AddWireContext *awc = cls;
85 : struct GNUNET_TIME_Timestamp last_date;
86 : enum GNUNET_DB_QueryStatus qs;
87 :
88 0 : qs = TEH_plugin->lookup_wire_timestamp (TEH_plugin->cls,
89 : awc->payto_uri,
90 : &last_date);
91 0 : if (qs < 0)
92 : {
93 0 : if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
94 0 : return qs;
95 0 : GNUNET_break (0);
96 0 : *mhd_ret = TALER_MHD_reply_with_error (connection,
97 : MHD_HTTP_INTERNAL_SERVER_ERROR,
98 : TALER_EC_GENERIC_DB_FETCH_FAILED,
99 : "lookup wire");
100 0 : return qs;
101 : }
102 0 : if ( (0 < qs) &&
103 0 : (GNUNET_TIME_timestamp_cmp (last_date,
104 : >,
105 : awc->validity_start)) )
106 : {
107 0 : *mhd_ret = TALER_MHD_reply_with_error (
108 : connection,
109 : MHD_HTTP_CONFLICT,
110 : TALER_EC_EXCHANGE_MANAGEMENT_WIRE_MORE_RECENT_PRESENT,
111 : NULL);
112 0 : return GNUNET_DB_STATUS_HARD_ERROR;
113 : }
114 0 : if (0 == qs)
115 0 : qs = TEH_plugin->insert_wire (TEH_plugin->cls,
116 : awc->payto_uri,
117 : awc->validity_start,
118 0 : &awc->master_sig_wire);
119 : else
120 0 : qs = TEH_plugin->update_wire (TEH_plugin->cls,
121 : awc->payto_uri,
122 : awc->validity_start,
123 : true);
124 0 : if (qs < 0)
125 : {
126 0 : GNUNET_break (0);
127 0 : if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
128 0 : return qs;
129 0 : *mhd_ret = TALER_MHD_reply_with_error (connection,
130 : MHD_HTTP_INTERNAL_SERVER_ERROR,
131 : TALER_EC_GENERIC_DB_STORE_FAILED,
132 : "add wire");
133 0 : return qs;
134 : }
135 0 : return qs;
136 : }
137 :
138 :
139 : MHD_RESULT
140 0 : TEH_handler_management_post_wire (
141 : struct MHD_Connection *connection,
142 : const json_t *root)
143 : {
144 : struct AddWireContext awc;
145 : struct GNUNET_JSON_Specification spec[] = {
146 0 : GNUNET_JSON_spec_fixed_auto ("master_sig_wire",
147 : &awc.master_sig_wire),
148 0 : GNUNET_JSON_spec_fixed_auto ("master_sig_add",
149 : &awc.master_sig_add),
150 0 : GNUNET_JSON_spec_string ("payto_uri",
151 : &awc.payto_uri),
152 0 : GNUNET_JSON_spec_timestamp ("validity_start",
153 : &awc.validity_start),
154 0 : GNUNET_JSON_spec_end ()
155 : };
156 :
157 : {
158 : enum GNUNET_GenericReturnValue res;
159 :
160 0 : res = TALER_MHD_parse_json_data (connection,
161 : root,
162 : spec);
163 0 : if (GNUNET_SYSERR == res)
164 0 : return MHD_NO; /* hard failure */
165 0 : if (GNUNET_NO == res)
166 0 : return MHD_YES; /* failure */
167 : }
168 0 : TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
169 : {
170 0 : char *msg = TALER_payto_validate (awc.payto_uri);
171 :
172 0 : if (NULL != msg)
173 : {
174 : MHD_RESULT ret;
175 :
176 0 : GNUNET_break_op (0);
177 0 : ret = TALER_MHD_reply_with_error (
178 : connection,
179 : MHD_HTTP_BAD_REQUEST,
180 : TALER_EC_GENERIC_PAYTO_URI_MALFORMED,
181 : msg);
182 0 : GNUNET_free (msg);
183 0 : return ret;
184 : }
185 : }
186 0 : if (GNUNET_OK !=
187 0 : TALER_exchange_offline_wire_add_verify (awc.payto_uri,
188 : awc.validity_start,
189 : &TEH_master_public_key,
190 : &awc.master_sig_add))
191 : {
192 0 : GNUNET_break_op (0);
193 0 : return TALER_MHD_reply_with_error (
194 : connection,
195 : MHD_HTTP_FORBIDDEN,
196 : TALER_EC_EXCHANGE_MANAGEMENT_WIRE_ADD_SIGNATURE_INVALID,
197 : NULL);
198 : }
199 0 : TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
200 0 : if (GNUNET_OK !=
201 0 : TALER_exchange_wire_signature_check (awc.payto_uri,
202 : &TEH_master_public_key,
203 : &awc.master_sig_wire))
204 : {
205 0 : GNUNET_break_op (0);
206 0 : return TALER_MHD_reply_with_error (
207 : connection,
208 : MHD_HTTP_FORBIDDEN,
209 : TALER_EC_EXCHANGE_MANAGEMENT_WIRE_DETAILS_SIGNATURE_INVALID,
210 : NULL);
211 : }
212 : {
213 : char *wire_method;
214 :
215 0 : wire_method = TALER_payto_get_method (awc.payto_uri);
216 0 : if (NULL == wire_method)
217 : {
218 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
219 : "payto:// URI `%s' is malformed\n",
220 : awc.payto_uri);
221 0 : return TALER_MHD_reply_with_error (
222 : connection,
223 : MHD_HTTP_BAD_REQUEST,
224 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
225 : "payto_uri");
226 : }
227 0 : GNUNET_free (wire_method);
228 : }
229 :
230 : {
231 : enum GNUNET_GenericReturnValue res;
232 : MHD_RESULT ret;
233 :
234 0 : res = TEH_DB_run_transaction (connection,
235 : "add wire",
236 : TEH_MT_REQUEST_OTHER,
237 : &ret,
238 : &add_wire,
239 : &awc);
240 0 : if (GNUNET_SYSERR == res)
241 0 : return ret;
242 : }
243 0 : TEH_wire_update_state ();
244 0 : return TALER_MHD_reply_static (
245 : connection,
246 : MHD_HTTP_NO_CONTENT,
247 : NULL,
248 : NULL,
249 : 0);
250 : }
251 :
252 :
253 : /* end of taler-exchange-httpd_management_wire.c */
|