Line data Source code
1 : /*
2 : This file is part of SYNC
3 : Copyright (C) 2014-2019 Taler Systems SA
4 :
5 : SYNC is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU General Public License as
7 : published by the Free Software Foundation; either version 3, or
8 : (at your option) any later version.
9 :
10 : SYNC is distributed in the hope that it will be useful, but
11 : WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public
16 : License along with SYNC; see the file COPYING. If not, see
17 : <http://www.gnu.org/licenses/>
18 : */
19 : /**
20 : * @file lib/testing_api_cmd_backup_upload.c
21 : * @brief command to upload data to the sync backend service.
22 : * @author Christian Grothoff
23 : */
24 : #include "platform.h"
25 : #include "sync_service.h"
26 : #include "sync_testing_lib.h"
27 : #include <taler/taler_util.h>
28 : #include <taler/taler_testing_lib.h>
29 : #include <taler/taler_merchant_service.h>
30 : #include "sync_testing_lib.h"
31 :
32 : /**
33 : * State for a "backup upload" CMD.
34 : */
35 : struct BackupUploadState
36 : {
37 :
38 : /**
39 : * Eddsa private key.
40 : */
41 : struct SYNC_AccountPrivateKeyP sync_priv;
42 :
43 : /**
44 : * Eddsa public key.
45 : */
46 : struct SYNC_AccountPublicKeyP sync_pub;
47 :
48 : /**
49 : * Hash of the previous upload (maybe bogus if
50 : * #SYNC_TESTING_UO_PREV_HASH_WRONG is set in @e uo).
51 : * Maybe all zeros if there was no previous upload.
52 : */
53 : struct GNUNET_HashCode prev_hash;
54 :
55 : /**
56 : * Hash of the current upload.
57 : */
58 : struct GNUNET_HashCode curr_hash;
59 :
60 : /**
61 : * The /backups POST operation handle.
62 : */
63 : struct SYNC_UploadOperation *uo;
64 :
65 : /**
66 : * URL of the sync backend.
67 : */
68 : const char *sync_url;
69 :
70 : /**
71 : * Previous upload, or NULL for none. Used to calculate what THIS
72 : * upload is based on.
73 : */
74 : const char *prev_upload;
75 :
76 : /**
77 : * Last upload, or NULL for none, usually same as @e prev_upload.
78 : * Used to check the response on #MHD_HTTP_CONFLICT.
79 : */
80 : const char *last_upload;
81 :
82 : /**
83 : * Payment order ID we got back, if any. Otherwise NULL.
84 : */
85 : const char *payment_order_id;
86 :
87 : /**
88 : * Claim token we got back, if any. Otherwise all zeros.
89 : */
90 : struct TALER_ClaimTokenP token;
91 :
92 : /**
93 : * Payment order ID we are to provide in the request, may be NULL.
94 : */
95 : const char *payment_order_req;
96 :
97 : /**
98 : * The interpreter state.
99 : */
100 : struct TALER_TESTING_Interpreter *is;
101 :
102 : /**
103 : * The backup data we are uploading.
104 : */
105 : const void *backup;
106 :
107 : /**
108 : * Number of bytes in @e backup.
109 : */
110 : size_t backup_size;
111 :
112 : /**
113 : * Expected status code.
114 : */
115 : unsigned int http_status;
116 :
117 : /**
118 : * Options for how we are supposed to do the upload.
119 : */
120 : enum SYNC_TESTING_UploadOption uopt;
121 :
122 : };
123 :
124 :
125 : /**
126 : * Function called with the results of a #SYNC_upload().
127 : *
128 : * @param cls closure
129 : * @param ec Taler error code
130 : * @param http_status HTTP status of the request
131 : * @param ud details about the upload operation
132 : */
133 : static void
134 0 : backup_upload_cb (void *cls,
135 : enum TALER_ErrorCode ec,
136 : unsigned int http_status,
137 : const struct SYNC_UploadDetails *ud)
138 : {
139 0 : struct BackupUploadState *bus = cls;
140 :
141 0 : bus->uo = NULL;
142 0 : if (http_status != bus->http_status)
143 : {
144 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
145 : "Unexpected response code %u to command %s in %s:%u\n",
146 : http_status,
147 : bus->is->commands[bus->is->ip].label,
148 : __FILE__,
149 : __LINE__);
150 0 : TALER_TESTING_interpreter_fail (bus->is);
151 0 : return;
152 : }
153 0 : if (NULL != ud)
154 : {
155 0 : switch (ud->us)
156 : {
157 0 : case SYNC_US_SUCCESS:
158 0 : if (0 != GNUNET_memcmp (&bus->curr_hash,
159 : ud->details.curr_backup_hash))
160 : {
161 0 : GNUNET_break (0);
162 0 : TALER_TESTING_interpreter_fail (bus->is);
163 0 : return;
164 : }
165 0 : break;
166 0 : case SYNC_US_PAYMENT_REQUIRED:
167 : {
168 : struct TALER_MERCHANT_PayUriData pd;
169 :
170 0 : if (GNUNET_OK !=
171 0 : TALER_MERCHANT_parse_pay_uri (ud->details.payment_request,
172 : &pd))
173 : {
174 0 : GNUNET_break (0);
175 0 : TALER_TESTING_interpreter_fail (bus->is);
176 0 : return;
177 : }
178 0 : bus->payment_order_id = GNUNET_strdup (pd.order_id);
179 0 : if (NULL != pd.claim_token)
180 0 : bus->token = *pd.claim_token;
181 0 : TALER_MERCHANT_parse_pay_uri_free (&pd);
182 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
183 : "Order ID from Sync service is `%s'\n",
184 : bus->payment_order_id);
185 0 : memset (&bus->curr_hash,
186 : 0,
187 : sizeof (struct GNUNET_HashCode));
188 : }
189 0 : break;
190 0 : case SYNC_US_CONFLICTING_BACKUP:
191 : {
192 : const struct TALER_TESTING_Command *ref;
193 : const struct GNUNET_HashCode *h;
194 :
195 0 : ref = TALER_TESTING_interpreter_lookup_command
196 : (bus->is,
197 : bus->last_upload);
198 0 : GNUNET_assert (NULL != ref);
199 0 : GNUNET_assert (GNUNET_OK ==
200 : SYNC_TESTING_get_trait_hash (ref,
201 : SYNC_TESTING_TRAIT_HASH_CURRENT,
202 : &h));
203 0 : if (0 != GNUNET_memcmp (h,
204 : &ud->details.recovered_backup.
205 : existing_backup_hash))
206 : {
207 0 : GNUNET_break (0);
208 0 : TALER_TESTING_interpreter_fail (bus->is);
209 0 : return;
210 : }
211 : }
212 : case SYNC_US_HTTP_ERROR:
213 0 : break;
214 0 : case SYNC_US_CLIENT_ERROR:
215 0 : GNUNET_break (0);
216 0 : TALER_TESTING_interpreter_fail (bus->is);
217 0 : return;
218 0 : case SYNC_US_SERVER_ERROR:
219 0 : GNUNET_break (0);
220 0 : TALER_TESTING_interpreter_fail (bus->is);
221 0 : return;
222 : }
223 0 : }
224 0 : TALER_TESTING_interpreter_next (bus->is);
225 : }
226 :
227 :
228 : /**
229 : * Run a "backup upload" CMD.
230 : *
231 : * @param cls closure.
232 : * @param cmd command currently being run.
233 : * @param is interpreter state.
234 : */
235 : static void
236 0 : backup_upload_run (void *cls,
237 : const struct TALER_TESTING_Command *cmd,
238 : struct TALER_TESTING_Interpreter *is)
239 : {
240 0 : struct BackupUploadState *bus = cls;
241 :
242 0 : bus->is = is;
243 0 : if (NULL != bus->prev_upload)
244 : {
245 : const struct TALER_TESTING_Command *ref;
246 :
247 0 : ref = TALER_TESTING_interpreter_lookup_command (
248 : is,
249 : bus->prev_upload);
250 0 : if (NULL == ref)
251 : {
252 0 : GNUNET_break (0);
253 0 : TALER_TESTING_interpreter_fail (bus->is);
254 0 : return;
255 : }
256 : {
257 : const struct GNUNET_HashCode *h;
258 :
259 0 : if (GNUNET_OK ==
260 0 : SYNC_TESTING_get_trait_hash (ref,
261 : SYNC_TESTING_TRAIT_HASH_CURRENT,
262 : &h))
263 : {
264 0 : bus->prev_hash = *h;
265 : }
266 : }
267 : {
268 : const struct SYNC_AccountPrivateKeyP *priv;
269 :
270 0 : if (GNUNET_OK !=
271 0 : SYNC_TESTING_get_trait_account_priv (ref,
272 : 0,
273 : &priv))
274 : {
275 0 : GNUNET_break (0);
276 0 : TALER_TESTING_interpreter_fail (bus->is);
277 0 : return;
278 : }
279 0 : bus->sync_priv = *priv;
280 : }
281 : {
282 : const struct SYNC_AccountPublicKeyP *pub;
283 :
284 0 : if (GNUNET_OK !=
285 0 : SYNC_TESTING_get_trait_account_pub (ref,
286 : 0,
287 : &pub))
288 : {
289 0 : GNUNET_break (0);
290 0 : TALER_TESTING_interpreter_fail (bus->is);
291 0 : return;
292 : }
293 0 : bus->sync_pub = *pub;
294 : }
295 0 : if (0 != (SYNC_TESTING_UO_REFERENCE_ORDER_ID & bus->uopt))
296 : {
297 : const char **order_id;
298 :
299 0 : if (GNUNET_OK !=
300 0 : TALER_TESTING_get_trait_order_id (ref,
301 : &order_id))
302 : {
303 0 : GNUNET_break (0);
304 0 : TALER_TESTING_interpreter_fail (bus->is);
305 0 : return;
306 : }
307 0 : bus->payment_order_req = *order_id;
308 0 : if (NULL == bus->payment_order_req)
309 : {
310 0 : GNUNET_break (0);
311 0 : TALER_TESTING_interpreter_fail (bus->is);
312 0 : return;
313 : }
314 : }
315 : }
316 : else
317 : {
318 0 : GNUNET_CRYPTO_eddsa_key_create (&bus->sync_priv.eddsa_priv);
319 0 : GNUNET_CRYPTO_eddsa_key_get_public (&bus->sync_priv.eddsa_priv,
320 : &bus->sync_pub.eddsa_pub);
321 : }
322 0 : if (0 != (SYNC_TESTING_UO_PREV_HASH_WRONG & bus->uopt))
323 0 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
324 0 : &bus->prev_hash,
325 : sizeof (struct GNUNET_HashCode));
326 0 : GNUNET_CRYPTO_hash (bus->backup,
327 : bus->backup_size,
328 : &bus->curr_hash);
329 0 : bus->uo = SYNC_upload (is->ctx,
330 : bus->sync_url,
331 : &bus->sync_priv,
332 0 : ( ( (NULL != bus->prev_upload) &&
333 0 : (GNUNET_NO == GNUNET_is_zero (
334 0 : &bus->prev_hash)) ) ||
335 : (0 != (SYNC_TESTING_UO_PREV_HASH_WRONG
336 0 : & bus->uopt)) )
337 : ? &bus->prev_hash
338 : : NULL,
339 : bus->backup_size,
340 : bus->backup,
341 0 : (0 != (SYNC_TESTING_UO_REQUEST_PAYMENT & bus->uopt))
342 : ? SYNC_PO_FORCE_PAYMENT
343 0 : : SYNC_PO_NONE,
344 : bus->payment_order_req,
345 : &backup_upload_cb,
346 : bus);
347 0 : if (NULL == bus->uo)
348 : {
349 0 : GNUNET_break (0);
350 0 : TALER_TESTING_interpreter_fail (bus->is);
351 0 : return;
352 : }
353 : }
354 :
355 :
356 : /**
357 : * Free the state of a "backup upload" CMD, and possibly
358 : * cancel it if it did not complete.
359 : *
360 : * @param cls closure.
361 : * @param cmd command being freed.
362 : */
363 : static void
364 0 : backup_upload_cleanup (void *cls,
365 : const struct TALER_TESTING_Command *cmd)
366 : {
367 0 : struct BackupUploadState *bus = cls;
368 :
369 0 : if (NULL != bus->uo)
370 : {
371 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
372 : "Command '%s' did not complete (backup upload)\n",
373 : cmd->label);
374 0 : SYNC_upload_cancel (bus->uo);
375 0 : bus->uo = NULL;
376 : }
377 0 : GNUNET_free (bus);
378 0 : }
379 :
380 :
381 : /**
382 : * Offer internal data to other commands.
383 : *
384 : * @param cls closure
385 : * @param ret[out] result (could be anything)
386 : * @param trait name of the trait
387 : * @param index index number of the object to extract.
388 : * @return #GNUNET_OK on success
389 : */
390 : static int
391 0 : backup_upload_traits (void *cls,
392 : const void **ret,
393 : const char *trait,
394 : unsigned int index)
395 : {
396 0 : struct BackupUploadState *bus = cls;
397 : struct TALER_TESTING_Trait straits[] = {
398 0 : SYNC_TESTING_make_trait_hash (SYNC_TESTING_TRAIT_HASH_CURRENT,
399 0 : &bus->curr_hash),
400 0 : SYNC_TESTING_make_trait_hash (SYNC_TESTING_TRAIT_HASH_PREVIOUS,
401 0 : &bus->prev_hash),
402 0 : TALER_TESTING_make_trait_claim_token (&bus->token),
403 0 : SYNC_TESTING_make_trait_account_pub (0,
404 0 : &bus->sync_pub),
405 0 : SYNC_TESTING_make_trait_account_priv (0,
406 0 : &bus->sync_priv),
407 0 : TALER_TESTING_make_trait_order_id (&bus->payment_order_id),
408 0 : TALER_TESTING_trait_end ()
409 : };
410 : struct TALER_TESTING_Trait ftraits[] = {
411 0 : TALER_TESTING_make_trait_claim_token (&bus->token),
412 0 : SYNC_TESTING_make_trait_account_pub (0,
413 0 : &bus->sync_pub),
414 0 : SYNC_TESTING_make_trait_account_priv (0,
415 0 : &bus->sync_priv),
416 0 : TALER_TESTING_make_trait_order_id (&bus->payment_order_id),
417 0 : TALER_TESTING_trait_end ()
418 : };
419 :
420 :
421 0 : return TALER_TESTING_get_trait ((NULL != bus->payment_order_req)
422 : ? ftraits
423 : : straits,
424 : ret,
425 : trait,
426 : index);
427 : }
428 :
429 :
430 : /**
431 : * Make the "backup upload" command.
432 : *
433 : * @param label command label
434 : * @param sync_url base URL of the sync serving
435 : * the policy store request.
436 : * @param prev_upload reference to a previous upload we are
437 : * supposed to update, NULL for none
438 : * @param last_upload reference to the last upload for the
439 : * same account, used to check result on MHD_HTTP_CONFLICT
440 : * @param uo upload options
441 : * @param http_status expected HTTP status.
442 : * @param backup_data data to upload
443 : * @param backup_data_size number of bytes in @a backup_data
444 : * @return the command
445 : */
446 : struct TALER_TESTING_Command
447 0 : SYNC_TESTING_cmd_backup_upload (const char *label,
448 : const char *sync_url,
449 : const char *prev_upload,
450 : const char *last_upload,
451 : enum SYNC_TESTING_UploadOption uo,
452 : unsigned int http_status,
453 : const void *backup_data,
454 : size_t backup_data_size)
455 : {
456 : struct BackupUploadState *bus;
457 :
458 0 : bus = GNUNET_new (struct BackupUploadState);
459 0 : bus->http_status = http_status;
460 0 : bus->prev_upload = prev_upload;
461 0 : bus->last_upload = last_upload;
462 0 : bus->uopt = uo;
463 0 : bus->sync_url = sync_url;
464 0 : bus->backup = backup_data;
465 0 : bus->backup_size = backup_data_size;
466 : {
467 0 : struct TALER_TESTING_Command cmd = {
468 : .cls = bus,
469 : .label = label,
470 : .run = &backup_upload_run,
471 : .cleanup = &backup_upload_cleanup,
472 : .traits = &backup_upload_traits
473 : };
474 :
475 0 : return cmd;
476 : }
477 : }
|