anastasis

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

anastasis-httpd_policy-meta.c (7018B)


      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 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   Anastasis 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   Anastasis; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file anastasis-httpd_policy-meta.c
     18  * @brief functions to handle incoming requests on /policy/$PID/meta
     19  * @author Christian Grothoff
     20  */
     21 #include "platform.h"
     22 #include "anastasis-httpd.h"
     23 #include "anastasis-httpd_policy-meta.h"
     24 #include "anastasis_service.h"
     25 #include <gnunet/gnunet_util_lib.h>
     26 #include <gnunet/gnunet_rest_lib.h>
     27 #include <taler/taler_json_lib.h>
     28 #include <taler/taler_merchant_service.h>
     29 #include <taler/taler_signatures.h>
     30 
     31 
     32 /**
     33  * Function called on matching meta data.  Note that if the client did
     34  * not provide meta data for @a version, the function will be called
     35  * with @a recovery_meta_data being NULL.
     36  *
     37  * @param cls closure with a `json_t *` to build up
     38  * @param version the version of the recovery document
     39  * @param ts timestamp when the document was created
     40  * @param recovery_meta_data contains meta data about the encrypted recovery document
     41  * @param recovery_meta_data_size size of @a recovery_meta_data blob
     42  * @return #GNUNET_OK to continue to iterate, #GNUNET_NO to abort iteration
     43  */
     44 static enum GNUNET_GenericReturnValue
     45 build_meta_result (void *cls,
     46                    uint32_t version,
     47                    struct GNUNET_TIME_Timestamp ts,
     48                    const void *recovery_meta_data,
     49                    size_t recovery_meta_data_size)
     50 {
     51   json_t *result = cls;
     52   char version_s[14];
     53 
     54   GNUNET_snprintf (version_s,
     55                    sizeof (version_s),
     56                    "%u",
     57                    (unsigned int) version);
     58   GNUNET_assert (0 ==
     59                  json_object_set_new (
     60                    result,
     61                    version_s,
     62                    GNUNET_JSON_PACK (
     63                      GNUNET_JSON_pack_data_varsize (
     64                        "meta",
     65                        recovery_meta_data,
     66                        recovery_meta_data_size),
     67                      GNUNET_JSON_pack_timestamp (
     68                        "upload_time",
     69                        ts))));
     70   return GNUNET_OK;
     71 }
     72 
     73 
     74 /**
     75  * Return the meta data on recovery documents of @a account on @a
     76  * connection.
     77  *
     78  * @param connection MHD connection to use
     79  * @param account_pub account to query
     80  * @return MHD result code
     81  */
     82 static MHD_RESULT
     83 return_policy_meta (
     84   struct MHD_Connection *connection,
     85   const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub)
     86 {
     87   enum GNUNET_DB_QueryStatus qs;
     88   uint32_t max_version = INT32_MAX; /* Postgres is using signed ints... */
     89   json_t *result;
     90 
     91   {
     92     const char *version_s;
     93 
     94     version_s = MHD_lookup_connection_value (connection,
     95                                              MHD_GET_ARGUMENT_KIND,
     96                                              "max_version");
     97     if (NULL != version_s)
     98     {
     99       char dummy;
    100 
    101       if (1 != sscanf (version_s,
    102                        "%u%c",
    103                        &max_version,
    104                        &dummy))
    105       {
    106         return TALER_MHD_reply_with_error (connection,
    107                                            MHD_HTTP_BAD_REQUEST,
    108                                            TALER_EC_GENERIC_PARAMETER_MALFORMED,
    109                                            "version");
    110       }
    111       if (max_version > INT32_MAX)
    112         max_version = INT32_MAX; /* cap to signed range */
    113     }
    114   }
    115   result = json_object ();
    116   GNUNET_assert (NULL != result);
    117   qs = db->get_recovery_meta_data (db->cls,
    118                                    account_pub,
    119                                    max_version,
    120                                    &build_meta_result,
    121                                    result);
    122 
    123   switch (qs)
    124   {
    125   case GNUNET_DB_STATUS_HARD_ERROR:
    126     GNUNET_break (0);
    127     return TALER_MHD_reply_with_error (connection,
    128                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    129                                        TALER_EC_GENERIC_DB_FETCH_FAILED,
    130                                        "get_recovery_document");
    131   case GNUNET_DB_STATUS_SOFT_ERROR:
    132     GNUNET_break (0);
    133     return TALER_MHD_reply_with_error (connection,
    134                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    135                                        TALER_EC_GENERIC_DB_SOFT_FAILURE,
    136                                        "get_recovery_document");
    137   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    138     return TALER_MHD_reply_with_error (connection,
    139                                        MHD_HTTP_NOT_FOUND,
    140                                        TALER_EC_ANASTASIS_POLICY_NOT_FOUND,
    141                                        NULL);
    142   default:
    143     /* interesting case below */
    144     break;
    145   }
    146 
    147   return TALER_MHD_reply_json_steal (connection,
    148                                      result,
    149                                      MHD_HTTP_OK);
    150 }
    151 
    152 
    153 MHD_RESULT
    154 AH_policy_meta_get (
    155   struct MHD_Connection *connection,
    156   const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub)
    157 {
    158   struct GNUNET_HashCode recovery_data_hash;
    159   enum ANASTASIS_DB_AccountStatus as;
    160   uint32_t version;
    161   struct GNUNET_TIME_Timestamp expiration;
    162 
    163   as = db->lookup_account (db->cls,
    164                            account_pub,
    165                            &expiration,
    166                            &recovery_data_hash,
    167                            &version);
    168   switch (as)
    169   {
    170   case ANASTASIS_DB_ACCOUNT_STATUS_PAYMENT_REQUIRED:
    171     return TALER_MHD_reply_with_error (connection,
    172                                        MHD_HTTP_NOT_FOUND,
    173                                        TALER_EC_ANASTASIS_POLICY_NOT_FOUND,
    174                                        "account expired: payment required");
    175   case ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR:
    176     GNUNET_break (0);
    177     return TALER_MHD_reply_with_error (connection,
    178                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    179                                        TALER_EC_GENERIC_DB_FETCH_FAILED,
    180                                        "lookup account");
    181   case ANASTASIS_DB_ACCOUNT_STATUS_NO_RESULTS:
    182     return TALER_MHD_reply_with_error (connection,
    183                                        MHD_HTTP_NOT_FOUND,
    184                                        TALER_EC_ANASTASIS_POLICY_NOT_FOUND,
    185                                        "no such account");
    186   case ANASTASIS_DB_ACCOUNT_STATUS_VALID_HASH_RETURNED:
    187     /* We have results, should fetch and return them! */
    188     break;
    189   }
    190   return return_policy_meta (connection,
    191                              account_pub);
    192 }