anastasis

Credential backup and recovery protocol and service
Log | Files | Refs | Submodules | README | LICENSE

anastasis_api_policy_meta_lookup.c (7573B)


      1 /*
      2   This file is part of ANASTASIS
      3   Copyright (C) 2022 Anastasis SARL
      4 
      5   ANASTASIS 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 2.1,
      8   or (at your option) any later version.
      9 
     10   ANASTASIS 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 ANASTASIS; see the file COPYING.LGPL.  If not,
     17   see <http://www.gnu.org/licenses/>
     18 */
     19 
     20 /**
     21  * @file restclient/anastasis_api_policy_meta_lookup.c
     22  * @brief Implementation of the /policy/$POL/meta GET request
     23  * @author Christian Grothoff
     24  */
     25 #include "platform.h"
     26 #include <curl/curl.h>
     27 #include <jansson.h>
     28 #include <microhttpd.h> /* just for HTTP status codes */
     29 #include "anastasis_service.h"
     30 #include "anastasis_api_curl_defaults.h"
     31 #include <gnunet/gnunet_json_lib.h>
     32 #include <taler/taler_signatures.h>
     33 
     34 
     35 /**
     36  * @brief A Meta Operation Handle
     37  */
     38 struct ANASTASIS_PolicyMetaLookupOperation
     39 {
     40 
     41   /**
     42    * The url for this request, including parameters.
     43    */
     44   char *url;
     45 
     46   /**
     47    * Handle for the request.
     48    */
     49   struct GNUNET_CURL_Job *job;
     50 
     51   /**
     52    * Function to call with the result.
     53    */
     54   ANASTASIS_PolicyMetaLookupCallback cb;
     55 
     56   /**
     57    * Closure for @a cb.
     58    */
     59   void *cb_cls;
     60 
     61   /**
     62    * Reference to the execution context.
     63    */
     64   struct GNUNET_CURL_Context *ctx;
     65 
     66   /**
     67    * Public key of the account we are downloading from.
     68    */
     69   struct ANASTASIS_CRYPTO_AccountPublicKeyP account_pub;
     70 
     71   /**
     72    * Maximum version to fetch.
     73    */
     74   uint32_t max_version;
     75 
     76 };
     77 
     78 
     79 /**
     80  * Process GET /policy/$POL/meta response
     81  *
     82  * @param cls our `struct ANASTASIS_PolicyMetaLookupOperation *`
     83  * @param response_code HTTP status
     84  * @param data response body, a `json_t *`, NULL on error
     85  */
     86 static void
     87 handle_policy_meta_lookup_finished (void *cls,
     88                                     long response_code,
     89                                     const void *response)
     90 {
     91   struct ANASTASIS_PolicyMetaLookupOperation *plo = cls;
     92   const json_t *json = response;
     93   struct ANASTASIS_MetaDownloadDetails mdd = {
     94     .http_status = response_code,
     95     .response = json
     96   };
     97 
     98   plo->job = NULL;
     99   switch (response_code)
    100   {
    101   case 0:
    102     /* Hard error */
    103     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    104                 "Backend didn't even return from GET /policy\n");
    105     break;
    106   case MHD_HTTP_OK:
    107     {
    108       size_t mlen = json_object_size (json);
    109 
    110       /* put a cap, as we will stack-allocate below and the
    111          current service LIMITs the result to 1000 anyway;
    112          could theoretically be increased in the future, but
    113          then we should not put this onto the stack anymore... */
    114       if (mlen > 10000)
    115       {
    116         GNUNET_break (0);
    117         response_code = 0;
    118         break;
    119       }
    120       {
    121         struct ANASTASIS_MetaDataEntry metas[GNUNET_NZL (mlen)];
    122         void *md[GNUNET_NZL (mlen)];
    123         size_t off = 0;
    124         const char *label;
    125         const json_t *val;
    126 
    127         memset (md,
    128                 0,
    129                 sizeof (md));
    130         mdd.details.ok.metas = metas;
    131         mdd.details.ok.metas_length = mlen;
    132         json_object_foreach ((json_t *) json,
    133                              label,
    134                              val)
    135         {
    136           unsigned int ver;
    137           char dummy;
    138           struct GNUNET_JSON_Specification spec[] = {
    139             GNUNET_JSON_spec_varsize ("meta",
    140                                       &md[off],
    141                                       &metas[off].meta_data_size),
    142             GNUNET_JSON_spec_timestamp ("upload_time",
    143                                         &metas[off].server_time),
    144             GNUNET_JSON_spec_end ()
    145           };
    146 
    147           if (1 != sscanf (label,
    148                            "%u%c",
    149                            &ver,
    150                            &dummy))
    151           {
    152             GNUNET_break (0);
    153             mdd.http_status = 0;
    154             mdd.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
    155             break;
    156           }
    157           if (GNUNET_OK !=
    158               GNUNET_JSON_parse (val,
    159                                  spec,
    160                                  NULL, NULL))
    161           {
    162             GNUNET_break_op (0);
    163             mdd.http_status = 0;
    164             mdd.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
    165             break;
    166           }
    167           metas[off].version = (uint32_t) ver;
    168           metas[off].meta_data = md[off];
    169           off++;
    170         }
    171         if (off < mlen)
    172         {
    173           GNUNET_break (0);
    174           mdd.http_status = 0;
    175           mdd.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
    176           for (size_t i = 0; i<off; i++)
    177             GNUNET_free (md[i]);
    178           break;
    179         }
    180         plo->cb (plo->cb_cls,
    181                  &mdd);
    182         for (size_t i = 0; i<off; i++)
    183           GNUNET_free (md[i]);
    184         plo->cb = NULL;
    185       }
    186       ANASTASIS_policy_meta_lookup_cancel (plo);
    187       return;
    188     }
    189   case MHD_HTTP_BAD_REQUEST:
    190     /* This should never happen, either us or the anastasis server is buggy
    191        (or API version conflict); just pass JSON reply to the application */
    192     break;
    193   case MHD_HTTP_NOT_FOUND:
    194     /* Nothing really to verify */
    195     break;
    196   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    197     /* Server had an internal issue; we should retry, but this API
    198        leaves this to the application */
    199     break;
    200   default:
    201     /* unexpected response code */
    202     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    203                 "Unexpected response code %u\n",
    204                 (unsigned int) response_code);
    205     GNUNET_break (0);
    206     break;
    207   }
    208   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    209               "HTTP status for policy meta lookup is %u\n",
    210               (unsigned int) response_code);
    211   plo->cb (plo->cb_cls,
    212            &mdd);
    213   plo->cb = NULL;
    214   ANASTASIS_policy_meta_lookup_cancel (plo);
    215 }
    216 
    217 
    218 struct ANASTASIS_PolicyMetaLookupOperation *
    219 ANASTASIS_policy_meta_lookup (
    220   struct GNUNET_CURL_Context *ctx,
    221   const char *backend_url,
    222   const struct ANASTASIS_CRYPTO_AccountPublicKeyP *anastasis_pub,
    223   uint32_t max_version,
    224   ANASTASIS_PolicyMetaLookupCallback cb,
    225   void *cb_cls)
    226 {
    227   struct ANASTASIS_PolicyMetaLookupOperation *plo;
    228   CURL *eh;
    229   char *path;
    230 
    231   // FIXME: pass 'max_version' in CURL request!
    232   GNUNET_assert (NULL != cb);
    233   plo = GNUNET_new (struct ANASTASIS_PolicyMetaLookupOperation);
    234   plo->account_pub = *anastasis_pub;
    235   {
    236     char *acc_pub_str;
    237 
    238     acc_pub_str = GNUNET_STRINGS_data_to_string_alloc (anastasis_pub,
    239                                                        sizeof (*anastasis_pub));
    240     GNUNET_asprintf (&path,
    241                      "policy/%s/meta",
    242                      acc_pub_str);
    243     GNUNET_free (acc_pub_str);
    244   }
    245   plo->url = TALER_url_join (backend_url,
    246                              path,
    247                              NULL);
    248   GNUNET_free (path);
    249   eh = ANASTASIS_curl_easy_get_ (plo->url);
    250   GNUNET_assert (NULL != eh);
    251   plo->cb = cb;
    252   plo->cb_cls = cb_cls;
    253   plo->job = GNUNET_CURL_job_add (ctx,
    254                                   eh,
    255                                   &handle_policy_meta_lookup_finished,
    256                                   plo);
    257   return plo;
    258 }
    259 
    260 
    261 void
    262 ANASTASIS_policy_meta_lookup_cancel (
    263   struct ANASTASIS_PolicyMetaLookupOperation *plo)
    264 {
    265   if (NULL != plo->job)
    266   {
    267     GNUNET_CURL_job_cancel (plo->job);
    268     plo->job = NULL;
    269   }
    270   GNUNET_free (plo->url);
    271   GNUNET_free (plo);
    272 }