diff options
Diffstat (limited to 'src/backend/anastasis-httpd_policy-meta.c')
-rw-r--r-- | src/backend/anastasis-httpd_policy-meta.c | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/src/backend/anastasis-httpd_policy-meta.c b/src/backend/anastasis-httpd_policy-meta.c new file mode 100644 index 0000000..67acc52 --- /dev/null +++ b/src/backend/anastasis-httpd_policy-meta.c @@ -0,0 +1,192 @@ +/* + This file is part of Anastasis + Copyright (C) 2022 Anastasis SARL + + Anastasis is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file anastasis-httpd_policy-meta.c + * @brief functions to handle incoming requests on /policy/$PID/meta + * @author Christian Grothoff + */ +#include "platform.h" +#include "anastasis-httpd.h" +#include "anastasis-httpd_policy-meta.h" +#include "anastasis_service.h" +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_rest_lib.h> +#include <taler/taler_json_lib.h> +#include <taler/taler_merchant_service.h> +#include <taler/taler_signatures.h> + + +/** + * Function called on matching meta data. Note that if the client did + * not provide meta data for @a version, the function will be called + * with @a recovery_meta_data being NULL. + * + * @param cls closure with a `json_t *` to build up + * @param version the version of the recovery document + * @param ts timestamp when the document was created + * @param recovery_meta_data contains meta data about the encrypted recovery document + * @param recovery_meta_data_size size of @a recovery_meta_data blob + * @return #GNUNET_OK to continue to iterate, #GNUNET_NO to abort iteration + */ +static enum GNUNET_GenericReturnValue +build_meta_result (void *cls, + uint32_t version, + struct GNUNET_TIME_Timestamp ts, + const void *recovery_meta_data, + size_t recovery_meta_data_size) +{ + json_t *result = cls; + char version_s[14]; + + GNUNET_snprintf (version_s, + sizeof (version_s), + "%u", + (unsigned int) version); + GNUNET_assert (0 == + json_object_set_new ( + result, + version_s, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_varsize ( + "meta", + recovery_meta_data, + recovery_meta_data_size), + GNUNET_JSON_pack_timestamp ( + "upload_time", + ts)))); + return GNUNET_OK; +} + + +/** + * Return the meta data on recovery documents of @a account on @a + * connection. + * + * @param connection MHD connection to use + * @param account_pub account to query + * @return MHD result code + */ +static MHD_RESULT +return_policy_meta ( + struct MHD_Connection *connection, + const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub) +{ + enum GNUNET_DB_QueryStatus qs; + uint32_t max_version = INT32_MAX; /* Postgres is using signed ints... */ + json_t *result; + + { + const char *version_s; + + version_s = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "max_version"); + if (NULL != version_s) + { + char dummy; + + if (1 != sscanf (version_s, + "%u%c", + &max_version, + &dummy)) + { + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "version"); + } + if (max_version > INT32_MAX) + max_version = INT32_MAX; /* cap to signed range */ + } + } + result = json_object (); + GNUNET_assert (NULL != result); + qs = db->get_recovery_meta_data (db->cls, + account_pub, + max_version, + &build_meta_result, + result); + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "get_recovery_document"); + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_SOFT_FAILURE, + "get_recovery_document"); + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_ANASTASIS_POLICY_NOT_FOUND, + NULL); + default: + /* interesting case below */ + break; + } + + return TALER_MHD_reply_json_steal (connection, + result, + MHD_HTTP_OK); +} + + +MHD_RESULT +AH_policy_meta_get ( + struct MHD_Connection *connection, + const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub) +{ + struct GNUNET_HashCode recovery_data_hash; + enum ANASTASIS_DB_AccountStatus as; + uint32_t version; + struct GNUNET_TIME_Timestamp expiration; + + as = db->lookup_account (db->cls, + account_pub, + &expiration, + &recovery_data_hash, + &version); + switch (as) + { + case ANASTASIS_DB_ACCOUNT_STATUS_PAYMENT_REQUIRED: + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_ANASTASIS_POLICY_NOT_FOUND, + "account expired: payment required"); + case ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR: + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "lookup account"); + case ANASTASIS_DB_ACCOUNT_STATUS_NO_RESULTS: + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_ANASTASIS_POLICY_NOT_FOUND, + "no such account"); + case ANASTASIS_DB_ACCOUNT_STATUS_VALID_HASH_RETURNED: + /* We have results, should fetch and return them! */ + break; + } + return return_policy_meta (connection, + account_pub); +} |