sync

Backup service to store encrypted wallet databases (experimental)
Log | Files | Refs | Submodules | README | LICENSE

testing_api_cmd_backup_upload.c (12644B)


      1 /*
      2   This file is part of SYNC
      3   Copyright (C) 2014-2023 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 testing/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 ud details about the upload operation
    130  */
    131 static void
    132 backup_upload_cb (void *cls,
    133                   const struct SYNC_UploadDetails *ud)
    134 {
    135   struct BackupUploadState *bus = cls;
    136 
    137   bus->uo = NULL;
    138   if (ud->http_status != bus->http_status)
    139   {
    140     TALER_TESTING_unexpected_status (bus->is,
    141                                      ud->http_status,
    142                                      bus->http_status);
    143     return;
    144   }
    145   switch (ud->us)
    146   {
    147   case SYNC_US_SUCCESS:
    148     if (0 != GNUNET_memcmp (
    149           &bus->curr_hash,
    150           ud->details.success.curr_backup_hash))
    151     {
    152       GNUNET_break (0);
    153       TALER_TESTING_interpreter_fail (bus->is);
    154       return;
    155     }
    156     break;
    157   case SYNC_US_PAYMENT_REQUIRED:
    158     {
    159       struct TALER_MERCHANT_PayUriData pd;
    160 
    161       if (GNUNET_OK !=
    162           TALER_MERCHANT_parse_pay_uri (
    163             ud->details.payment_required.payment_request,
    164             &pd))
    165       {
    166         GNUNET_break (0);
    167         TALER_TESTING_interpreter_fail (bus->is);
    168         return;
    169       }
    170       bus->payment_order_id = GNUNET_strdup (pd.order_id);
    171       if (NULL != pd.claim_token)
    172         bus->token = *pd.claim_token;
    173       TALER_MERCHANT_parse_pay_uri_free (&pd);
    174       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    175                   "Order ID from Sync service is `%s'\n",
    176                   bus->payment_order_id);
    177       memset (&bus->curr_hash,
    178               0,
    179               sizeof (struct GNUNET_HashCode));
    180     }
    181     break;
    182   case SYNC_US_CONFLICTING_BACKUP:
    183     {
    184       const struct TALER_TESTING_Command *ref;
    185       const struct GNUNET_HashCode *h;
    186 
    187       ref = TALER_TESTING_interpreter_lookup_command
    188               (bus->is,
    189               bus->last_upload);
    190       GNUNET_assert (NULL != ref);
    191       GNUNET_assert (GNUNET_OK ==
    192                      TALER_TESTING_get_trait_curr_hash (ref,
    193                                                         &h));
    194       if (0 != GNUNET_memcmp (h,
    195                               &ud->details.recovered_backup.
    196                               existing_backup_hash))
    197       {
    198         GNUNET_break (0);
    199         TALER_TESTING_interpreter_fail (bus->is);
    200         return;
    201       }
    202     }
    203   case SYNC_US_HTTP_ERROR:
    204     break;
    205   case SYNC_US_CLIENT_ERROR:
    206     GNUNET_break (0);
    207     TALER_TESTING_interpreter_fail (bus->is);
    208     return;
    209   case SYNC_US_SERVER_ERROR:
    210     GNUNET_break (0);
    211     TALER_TESTING_interpreter_fail (bus->is);
    212     return;
    213   }
    214   TALER_TESTING_interpreter_next (bus->is);
    215 }
    216 
    217 
    218 /**
    219  * Run a "backup upload" CMD.
    220  *
    221  * @param cls closure.
    222  * @param cmd command currently being run.
    223  * @param is interpreter state.
    224  */
    225 static void
    226 backup_upload_run (void *cls,
    227                    const struct TALER_TESTING_Command *cmd,
    228                    struct TALER_TESTING_Interpreter *is)
    229 {
    230   struct BackupUploadState *bus = cls;
    231 
    232   bus->is = is;
    233   if (NULL != bus->prev_upload)
    234   {
    235     const struct TALER_TESTING_Command *ref;
    236 
    237     ref = TALER_TESTING_interpreter_lookup_command (
    238       is,
    239       bus->prev_upload);
    240     if (NULL == ref)
    241     {
    242       GNUNET_break (0);
    243       TALER_TESTING_interpreter_fail (bus->is);
    244       return;
    245     }
    246     {
    247       const struct GNUNET_HashCode *h;
    248 
    249       if (GNUNET_OK ==
    250           TALER_TESTING_get_trait_curr_hash (ref,
    251                                              &h))
    252       {
    253         bus->prev_hash = *h;
    254       }
    255     }
    256     {
    257       const struct SYNC_AccountPrivateKeyP *priv;
    258 
    259       if (GNUNET_OK !=
    260           TALER_TESTING_get_trait_sync_account_priv (ref,
    261                                                      &priv))
    262       {
    263         GNUNET_break (0);
    264         TALER_TESTING_interpreter_fail (bus->is);
    265         return;
    266       }
    267       bus->sync_priv = *priv;
    268     }
    269     {
    270       const struct SYNC_AccountPublicKeyP *pub;
    271 
    272       if (GNUNET_OK !=
    273           TALER_TESTING_get_trait_sync_account_pub (ref,
    274                                                     &pub))
    275       {
    276         GNUNET_break (0);
    277         TALER_TESTING_interpreter_fail (bus->is);
    278         return;
    279       }
    280       bus->sync_pub = *pub;
    281     }
    282     if (0 != (SYNC_TESTING_UO_REFERENCE_ORDER_ID & bus->uopt))
    283     {
    284       const char *order_id;
    285 
    286       if (GNUNET_OK !=
    287           TALER_TESTING_get_trait_order_id (ref,
    288                                             &order_id))
    289       {
    290         GNUNET_break (0);
    291         TALER_TESTING_interpreter_fail (bus->is);
    292         return;
    293       }
    294       bus->payment_order_req = order_id;
    295       if (NULL == bus->payment_order_req)
    296       {
    297         GNUNET_break (0);
    298         TALER_TESTING_interpreter_fail (bus->is);
    299         return;
    300       }
    301     }
    302   }
    303   else
    304   {
    305     GNUNET_CRYPTO_eddsa_key_create (&bus->sync_priv.eddsa_priv);
    306     GNUNET_CRYPTO_eddsa_key_get_public (&bus->sync_priv.eddsa_priv,
    307                                         &bus->sync_pub.eddsa_pub);
    308   }
    309   if (0 != (SYNC_TESTING_UO_PREV_HASH_WRONG & bus->uopt))
    310     GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
    311                                 &bus->prev_hash,
    312                                 sizeof (struct GNUNET_HashCode));
    313   GNUNET_CRYPTO_hash (bus->backup,
    314                       bus->backup_size,
    315                       &bus->curr_hash);
    316   bus->uo = SYNC_upload (TALER_TESTING_interpreter_get_context (is),
    317                          bus->sync_url,
    318                          &bus->sync_priv,
    319                          ( ( (NULL != bus->prev_upload) &&
    320                              (GNUNET_NO == GNUNET_is_zero (
    321                                 &bus->prev_hash)) ) ||
    322                            (0 != (SYNC_TESTING_UO_PREV_HASH_WRONG
    323                                   & bus->uopt)) )
    324                          ? &bus->prev_hash
    325                          : NULL,
    326                          bus->backup_size,
    327                          bus->backup,
    328                          (0 != (SYNC_TESTING_UO_REQUEST_PAYMENT & bus->uopt))
    329                          ? SYNC_PO_FORCE_PAYMENT
    330                          : SYNC_PO_NONE,
    331                          bus->payment_order_req,
    332                          &backup_upload_cb,
    333                          bus);
    334   if (NULL == bus->uo)
    335   {
    336     GNUNET_break (0);
    337     TALER_TESTING_interpreter_fail (bus->is);
    338     return;
    339   }
    340 }
    341 
    342 
    343 /**
    344  * Free the state of a "backup upload" CMD, and possibly
    345  * cancel it if it did not complete.
    346  *
    347  * @param cls closure.
    348  * @param cmd command being freed.
    349  */
    350 static void
    351 backup_upload_cleanup (void *cls,
    352                        const struct TALER_TESTING_Command *cmd)
    353 {
    354   struct BackupUploadState *bus = cls;
    355 
    356   if (NULL != bus->uo)
    357   {
    358     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    359                 "Command '%s' did not complete (backup upload)\n",
    360                 cmd->label);
    361     SYNC_upload_cancel (bus->uo);
    362     bus->uo = NULL;
    363   }
    364   GNUNET_free (bus);
    365 }
    366 
    367 
    368 /**
    369  * Offer internal data to other commands.
    370  *
    371  * @param cls closure
    372  * @param[out] ret result (could be anything)
    373  * @param trait name of the trait
    374  * @param index index number of the object to extract.
    375  * @return #GNUNET_OK on success
    376  */
    377 static enum GNUNET_GenericReturnValue
    378 backup_upload_traits (void *cls,
    379                       const void **ret,
    380                       const char *trait,
    381                       unsigned int index)
    382 {
    383   struct BackupUploadState *bus = cls;
    384   struct TALER_TESTING_Trait straits[] = {
    385     TALER_TESTING_make_trait_curr_hash (&bus->curr_hash),
    386     TALER_TESTING_make_trait_prev_hash (&bus->prev_hash),
    387     TALER_TESTING_make_trait_claim_token (&bus->token),
    388     TALER_TESTING_make_trait_sync_account_pub (&bus->sync_pub),
    389     TALER_TESTING_make_trait_sync_account_priv (&bus->sync_priv),
    390     TALER_TESTING_make_trait_order_id (bus->payment_order_id),
    391     TALER_TESTING_trait_end ()
    392   };
    393   struct TALER_TESTING_Trait ftraits[] = {
    394     TALER_TESTING_make_trait_claim_token (&bus->token),
    395     TALER_TESTING_make_trait_sync_account_pub (&bus->sync_pub),
    396     TALER_TESTING_make_trait_sync_account_priv (&bus->sync_priv),
    397     TALER_TESTING_make_trait_order_id (bus->payment_order_id),
    398     TALER_TESTING_trait_end ()
    399   };
    400 
    401 
    402   return TALER_TESTING_get_trait ((NULL != bus->payment_order_req)
    403                                   ? ftraits
    404                                   : straits,
    405                                   ret,
    406                                   trait,
    407                                   index);
    408 }
    409 
    410 
    411 /**
    412  * Make the "backup upload" command.
    413  *
    414  * @param label command label
    415  * @param sync_url base URL of the sync serving
    416  *        the policy store request.
    417  * @param prev_upload reference to a previous upload we are
    418  *        supposed to update, NULL for none
    419  * @param last_upload reference to the last upload for the
    420  *          same account, used to check result on MHD_HTTP_CONFLICT
    421  * @param uo upload options
    422  * @param http_status expected HTTP status.
    423  * @param backup_data data to upload
    424  * @param backup_data_size number of bytes in @a backup_data
    425  * @return the command
    426  */
    427 struct TALER_TESTING_Command
    428 SYNC_TESTING_cmd_backup_upload (const char *label,
    429                                 const char *sync_url,
    430                                 const char *prev_upload,
    431                                 const char *last_upload,
    432                                 enum SYNC_TESTING_UploadOption uo,
    433                                 unsigned int http_status,
    434                                 const void *backup_data,
    435                                 size_t backup_data_size)
    436 {
    437   struct BackupUploadState *bus;
    438 
    439   bus = GNUNET_new (struct BackupUploadState);
    440   bus->http_status = http_status;
    441   bus->prev_upload = prev_upload;
    442   bus->last_upload = last_upload;
    443   bus->uopt = uo;
    444   bus->sync_url = sync_url;
    445   bus->backup = backup_data;
    446   bus->backup_size = backup_data_size;
    447   {
    448     struct TALER_TESTING_Command cmd = {
    449       .cls = bus,
    450       .label = label,
    451       .run = &backup_upload_run,
    452       .cleanup = &backup_upload_cleanup,
    453       .traits = &backup_upload_traits
    454     };
    455 
    456     return cmd;
    457   }
    458 }