sync

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

sync_api_block_list.c (5844B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2026 Taler Systems SA
      4 
      5   TALER 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   TALER 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 TALER; see the file COPYING.  If not, see
     17   <http://www.gnu.org/licenses/>
     18 */
     19 /**
     20  * @file lib/sync_api_block_list.c
     21  * @brief Implementation of the block list GET
     22  * @author Iván Ávalos
     23  */
     24 #include "platform.h"
     25 #include <curl/curl.h>
     26 #include <jansson.h>
     27 #include <microhttpd.h>
     28 #include <gnunet/gnunet_util_lib.h>
     29 #include <gnunet/gnunet_curl_lib.h>
     30 #include <gnunet/gnunet_json_lib.h>
     31 #include <taler/taler_json_lib.h>
     32 #include <taler/taler_curl_lib.h>
     33 #include <sync/sync_service.h>
     34 #include <sync/sync_util.h>
     35 #include "sync_api_curl_defaults.h"
     36 
     37 
     38 /**
     39  * Handle for a block list operation.
     40  */
     41 struct SYNC_BlockListOperation
     42 {
     43 
     44   /**
     45    * The url for this request.
     46    */
     47   char *url;
     48 
     49   /**
     50    * Handle for the request.
     51    */
     52   struct GNUNET_CURL_Job *job;
     53 
     54   /**
     55    * Reference to the execution context.
     56    */
     57   struct GNUNET_CURL_Context *ctx;
     58 
     59   /**
     60    * Function to call with the result.
     61    */
     62   SYNC_BlockListCallback cb;
     63 
     64   /**
     65    * Closure for @e cb.
     66    */
     67   void *cb_cls;
     68 
     69 };
     70 
     71 
     72 /**
     73  * Function called when we're done processing the
     74  * GET /backups/$KEY/blocks request.
     75  *
     76  * @param cls the `struct SYNC_BlockListOperation *`
     77  * @param response_code HTTP response code, 0 on error
     78  * @param response response body as parsed JSON, or NULL
     79  */
     80 static void
     81 handle_block_list_finished (void *cls,
     82                             long response_code,
     83                             const void *response)
     84 {
     85   struct SYNC_BlockListOperation *op = cls;
     86   const json_t *json = response;
     87   struct SYNC_BlockListDetails ld = {
     88     .http_status = (unsigned int) response_code,
     89     .ec = TALER_EC_INVALID
     90   };
     91 
     92   op->job = NULL;
     93   switch (response_code)
     94   {
     95   case 0:
     96     break;
     97   case MHD_HTTP_OK:
     98     if (NULL != json)
     99     {
    100       unsigned int idx;
    101       json_t *entry;
    102 
    103       ld.ec = TALER_EC_NONE;
    104       ld.num_entries = json_array_size (json);
    105       ld.entries = GNUNET_new_array (ld.num_entries,
    106                                      struct SYNC_BlockListEntry);
    107       json_array_foreach (json, idx, entry)
    108       {
    109         struct SYNC_BlockListEntry *e = &ld.entries[idx];
    110 
    111         if (GNUNET_OK !=
    112             SYNC_block_entry_parse (entry,
    113                                     e))
    114         {
    115           GNUNET_break_op (0);
    116           ld.ec = TALER_EC_GENERIC_PARAMETER_MALFORMED;
    117           break;
    118         }
    119       }
    120     }
    121     else
    122     {
    123       ld.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    124     }
    125     break;
    126   case MHD_HTTP_BAD_REQUEST:
    127   case MHD_HTTP_NOT_FOUND:
    128   case MHD_HTTP_PAYMENT_REQUIRED:
    129   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    130   default:
    131     if ( (response_code >= 400) &&
    132          (response_code < 500) )
    133       ld.ec = (NULL != json)
    134               ? TALER_JSON_get_error_code (json)
    135               : TALER_EC_GENERIC_PARAMETER_MALFORMED;
    136     else if (response_code >= 500)
    137       ld.ec = (NULL != json)
    138               ? TALER_JSON_get_error_code (json)
    139               : TALER_EC_GENERIC_INVALID_RESPONSE;
    140     break;
    141   }
    142   if (NULL != op->cb)
    143   {
    144     op->cb (op->cb_cls,
    145             &ld);
    146     op->cb = NULL;
    147   }
    148   if (NULL != ld.entries)
    149   {
    150     for (unsigned int i = 0; i < ld.num_entries; i++)
    151       SYNC_block_entry_clear (&ld.entries[i]);
    152     GNUNET_free (ld.entries);
    153   }
    154   SYNC_block_list_cancel (op);
    155 }
    156 
    157 
    158 struct SYNC_BlockListOperation *
    159 SYNC_block_list (struct GNUNET_CURL_Context *ctx,
    160                  const char *base_url,
    161                  const struct SYNC_AccountPublicKeyP *pub,
    162                  int16_t limit,
    163                  const struct SYNC_BlockNonce *start_nonce,
    164                  SYNC_BlockListCallback cb,
    165                  void *cb_cls)
    166 {
    167   struct SYNC_BlockListOperation *op;
    168   CURL *eh;
    169   char *pub_s;
    170   char *nonce_s = NULL;
    171   char *path;
    172   char *limit_s;
    173   char *url;
    174 
    175   pub_s = GNUNET_STRINGS_data_to_string_alloc (pub,
    176                                                sizeof (*pub));
    177   GNUNET_asprintf (&path,
    178                    "backups/%s/blocks",
    179                    pub_s);
    180   GNUNET_free (pub_s);
    181   GNUNET_asprintf (&limit_s,
    182                    "%d",
    183                    (int) limit);
    184   if (NULL != start_nonce)
    185     nonce_s = GNUNET_STRINGS_data_to_string_alloc (
    186       start_nonce,
    187       sizeof (*start_nonce));
    188   url = TALER_url_join (base_url,
    189                         path,
    190                         "limit",
    191                         limit_s,
    192                         "start_nonce",
    193                         nonce_s,
    194                         NULL);
    195   GNUNET_free (nonce_s);
    196   GNUNET_free (limit_s);
    197   GNUNET_free (path);
    198   if (NULL == url)
    199   {
    200     GNUNET_break (0);
    201     return NULL;
    202   }
    203 
    204   op = GNUNET_new (struct SYNC_BlockListOperation);
    205   op->ctx = ctx;
    206   op->cb = cb;
    207   op->cb_cls = cb_cls;
    208   op->url = url;
    209 
    210   eh = SYNC_curl_easy_get_ (op->url);
    211   if (NULL == eh)
    212   {
    213     GNUNET_break (0);
    214     GNUNET_free (op->url);
    215     GNUNET_free (op);
    216     return NULL;
    217   }
    218 
    219   op->job = GNUNET_CURL_job_add2 (ctx,
    220                                   eh,
    221                                   NULL,
    222                                   &handle_block_list_finished,
    223                                   op);
    224   return op;
    225 }
    226 
    227 
    228 void
    229 SYNC_block_list_cancel (struct SYNC_BlockListOperation *op)
    230 {
    231   if (NULL != op->job)
    232   {
    233     GNUNET_CURL_job_cancel (op->job);
    234     op->job = NULL;
    235   }
    236   GNUNET_free (op->url);
    237   GNUNET_free (op);
    238 }