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 }