aboutsummaryrefslogtreecommitdiff
path: root/src/backend/anastasis-httpd_policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/anastasis-httpd_policy.c')
-rw-r--r--src/backend/anastasis-httpd_policy.c252
1 files changed, 252 insertions, 0 deletions
diff --git a/src/backend/anastasis-httpd_policy.c b/src/backend/anastasis-httpd_policy.c
new file mode 100644
index 0000000..2417e15
--- /dev/null
+++ b/src/backend/anastasis-httpd_policy.c
@@ -0,0 +1,252 @@
1/*
2 This file is part of TALER
3 Copyright (C) 2019, 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 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 anastasis-httpd_policy.c
18 * @brief functions to handle incoming requests on /policy/
19 * @author Dennis Neufeld
20 * @author Dominik Meister
21 * @author Christian Grothoff
22 */
23#include "platform.h"
24#include "anastasis-httpd.h"
25#include "anastasis-httpd_policy.h"
26#include "anastasis_service.h"
27#include <gnunet/gnunet_util_lib.h>
28#include <gnunet/gnunet_rest_lib.h>
29#include <taler/taler_json_lib.h>
30#include <taler/taler_merchant_service.h>
31#include <taler/taler_signatures.h>
32
33/**
34 * How long do we hold an HTTP client connection if
35 * we are awaiting payment before giving up?
36 */
37#define CHECK_PAYMENT_GENERIC_TIMEOUT GNUNET_TIME_relative_multiply ( \
38 GNUNET_TIME_UNIT_MINUTES, 30)
39
40
41/**
42 * Return the current recoverydocument of @a account on @a connection
43 * using @a default_http_status on success.
44 *
45 * @param connection MHD connection to use
46 * @param account account to query
47 * @return MHD result code
48 */
49static MHD_RESULT
50return_policy (struct MHD_Connection *connection,
51 const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub)
52{
53 enum GNUNET_DB_QueryStatus qs;
54 struct MHD_Response *resp;
55 struct ANASTASIS_AccountSignatureP account_sig;
56 struct GNUNET_HashCode recovery_data_hash;
57 const char *version_s;
58 char version_b[14];
59 uint32_t version;
60 void *res_recovery_data;
61 size_t res_recovery_data_size;
62
63 version_s = MHD_lookup_connection_value (connection,
64 MHD_GET_ARGUMENT_KIND,
65 "version");
66 if (NULL != version_s)
67 {
68 char dummy;
69
70 if (1 != sscanf (version_s,
71 "%u%c",
72 &version,
73 &dummy))
74 {
75 return TALER_MHD_reply_with_error (connection,
76 MHD_HTTP_BAD_REQUEST,
77 TALER_EC_GENERIC_PARAMETER_MALFORMED,
78 "version");
79 }
80 qs = db->get_recovery_document (db->cls,
81 account_pub,
82 version,
83 &account_sig,
84 &recovery_data_hash,
85 &res_recovery_data_size,
86 &res_recovery_data);
87 }
88 else
89 {
90 qs = db->get_latest_recovery_document (db->cls,
91 account_pub,
92 &account_sig,
93 &recovery_data_hash,
94 &res_recovery_data_size,
95 &res_recovery_data,
96 &version);
97 GNUNET_snprintf (version_b,
98 sizeof (version_b),
99 "%u",
100 (unsigned int) version);
101 version_s = version_b;
102 }
103 switch (qs)
104 {
105 case GNUNET_DB_STATUS_HARD_ERROR:
106 GNUNET_break (0);
107 return TALER_MHD_reply_with_error (connection,
108 MHD_HTTP_INTERNAL_SERVER_ERROR,
109 TALER_EC_GENERIC_DB_FETCH_FAILED,
110 "get_recovery_document");
111 case GNUNET_DB_STATUS_SOFT_ERROR:
112 GNUNET_break (0);
113 return TALER_MHD_reply_with_error (connection,
114 MHD_HTTP_INTERNAL_SERVER_ERROR,
115 TALER_EC_GENERIC_DB_SOFT_FAILURE,
116 "get_recovery_document");
117 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
118 return TALER_MHD_reply_with_error (connection,
119 MHD_HTTP_NOT_FOUND,
120 TALER_EC_ANASTASIS_POLICY_NOT_FOUND,
121 NULL);
122 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
123 /* interesting case below */
124 break;
125 }
126 resp = MHD_create_response_from_buffer (res_recovery_data_size,
127 res_recovery_data,
128 MHD_RESPMEM_MUST_FREE);
129 TALER_MHD_add_global_headers (resp);
130 {
131 char *sig_s;
132 char *etag;
133
134 sig_s = GNUNET_STRINGS_data_to_string_alloc (&account_sig,
135 sizeof (account_sig));
136 etag = GNUNET_STRINGS_data_to_string_alloc (&recovery_data_hash,
137 sizeof (recovery_data_hash));
138 GNUNET_break (MHD_YES ==
139 MHD_add_response_header (resp,
140 ANASTASIS_HTTP_HEADER_POLICY_SIGNATURE,
141 sig_s));
142 GNUNET_break (MHD_YES ==
143 MHD_add_response_header (resp,
144 ANASTASIS_HTTP_HEADER_POLICY_VERSION,
145 version_s));
146 GNUNET_break (MHD_YES ==
147 MHD_add_response_header (resp,
148 MHD_HTTP_HEADER_ETAG,
149 etag));
150 GNUNET_free (etag);
151 GNUNET_free (sig_s);
152 }
153 {
154 MHD_RESULT ret;
155
156 ret = MHD_queue_response (connection,
157 MHD_HTTP_OK,
158 resp);
159 MHD_destroy_response (resp);
160 return ret;
161 }
162}
163
164
165MHD_RESULT
166AH_policy_get (struct MHD_Connection *connection,
167 const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub)
168{
169 struct GNUNET_HashCode recovery_data_hash;
170 enum ANASTASIS_DB_AccountStatus as;
171 MHD_RESULT ret;
172 uint32_t version;
173 struct GNUNET_TIME_Absolute expiration;
174
175 as = db->lookup_account (db->cls,
176 account_pub,
177 &expiration,
178 &recovery_data_hash,
179 &version);
180 switch (as)
181 {
182 case ANASTASIS_DB_ACCOUNT_STATUS_PAYMENT_REQUIRED:
183 return TALER_MHD_reply_with_error (connection,
184 MHD_HTTP_NOT_FOUND,
185 TALER_EC_SYNC_ACCOUNT_UNKNOWN,
186 NULL);
187 case ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR:
188 GNUNET_break (0);
189 return TALER_MHD_reply_with_error (connection,
190 MHD_HTTP_INTERNAL_SERVER_ERROR,
191 TALER_EC_GENERIC_DB_FETCH_FAILED,
192 "lookup account");
193 case ANASTASIS_DB_ACCOUNT_STATUS_NO_RESULTS:
194 {
195 struct MHD_Response *resp;
196
197 resp = MHD_create_response_from_buffer (0,
198 NULL,
199 MHD_RESPMEM_PERSISTENT);
200 TALER_MHD_add_global_headers (resp);
201 ret = MHD_queue_response (connection,
202 MHD_HTTP_NO_CONTENT,
203 resp);
204 MHD_destroy_response (resp);
205 }
206 return ret;
207 case ANASTASIS_DB_ACCOUNT_STATUS_VALID_HASH_RETURNED:
208 {
209 const char *inm;
210
211 inm = MHD_lookup_connection_value (connection,
212 MHD_HEADER_KIND,
213 MHD_HTTP_HEADER_IF_NONE_MATCH);
214 if (NULL != inm)
215 {
216 struct GNUNET_HashCode inm_h;
217
218 if (GNUNET_OK !=
219 GNUNET_STRINGS_string_to_data (inm,
220 strlen (inm),
221 &inm_h,
222 sizeof (inm_h)))
223 {
224 GNUNET_break_op (0);
225 return TALER_MHD_reply_with_error (connection,
226 MHD_HTTP_BAD_REQUEST,
227 TALER_EC_ANASTASIS_POLICY_BAD_IF_NONE_MATCH,
228 "Etag must be a base32-encoded SHA-512 hash");
229 }
230 if (0 == GNUNET_memcmp (&inm_h,
231 &recovery_data_hash))
232 {
233 struct MHD_Response *resp;
234
235 resp = MHD_create_response_from_buffer (0,
236 NULL,
237 MHD_RESPMEM_PERSISTENT);
238 TALER_MHD_add_global_headers (resp);
239 ret = MHD_queue_response (connection,
240 MHD_HTTP_NOT_MODIFIED,
241 resp);
242 MHD_destroy_response (resp);
243 return ret;
244 }
245 }
246 }
247 /* We have a result, should fetch and return it! */
248 break;
249 }
250 return return_policy (connection,
251 account_pub);
252}