[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-anastasis] branch master updated: enable payment for truth upload
From: |
gnunet |
Subject: |
[taler-anastasis] branch master updated: enable payment for truth upload, misc fixes |
Date: |
Wed, 10 Feb 2021 16:44:43 +0100 |
This is an automated email from the git hooks/post-receive script.
grothoff pushed a commit to branch master
in repository anastasis.
The following commit(s) were added to refs/heads/master by this push:
new 2368c23 enable payment for truth upload, misc fixes
2368c23 is described below
commit 2368c238c574287fa2fa50ee8da2cbef035b2251
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Wed Feb 10 16:44:41 2021 +0100
enable payment for truth upload, misc fixes
---
contrib/gana | 2 +-
src/backend/anastasis-httpd.c | 49 +++
src/backend/anastasis-httpd.h | 8 +-
src/backend/anastasis-httpd_policy.c | 24 +-
src/backend/anastasis-httpd_policy.h | 2 +
src/backend/anastasis-httpd_policy_upload.c | 166 +++-----
src/backend/anastasis-httpd_truth.c | 11 +-
src/backend/anastasis-httpd_truth.h | 16 +
src/backend/anastasis-httpd_truth_upload.c | 547 +++++++++++++++++++++++--
src/include/anastasis.h | 452 +++++++++++---------
src/include/anastasis_database_plugin.h | 32 ++
src/include/anastasis_service.h | 168 ++++++--
src/lib/anastasis_recovery.c | 186 ++++-----
src/reducer/anastasis_api_backup_redux.c | 6 +-
src/reducer/anastasis_api_redux.c | 18 +-
src/restclient/anastasis_api_keyshare_lookup.c | 263 ++++++++++--
src/restclient/anastasis_api_truth_store.c | 13 -
src/stasis/plugin_anastasis_postgres.c | 82 ++++
src/stasis/stasis-0001.sql | 29 +-
19 files changed, 1521 insertions(+), 553 deletions(-)
diff --git a/contrib/gana b/contrib/gana
index 5de7cb5..cb43a26 160000
--- a/contrib/gana
+++ b/contrib/gana
@@ -1 +1 @@
-Subproject commit 5de7cb5209109f97d56f7dd99262f24b0988c6b8
+Subproject commit cb43a2642dd75f21c45392667e0877c97474915b
diff --git a/src/backend/anastasis-httpd.c b/src/backend/anastasis-httpd.c
index 004bc7a..dcb0d3d 100644
--- a/src/backend/anastasis-httpd.c
+++ b/src/backend/anastasis-httpd.c
@@ -47,6 +47,11 @@ unsigned long long int AH_upload_limit_mb;
*/
struct TALER_Amount AH_annual_fee;
+/**
+ * Fee for a truth upload.
+ */
+struct TALER_Amount AH_truth_upload_fee;
+
/**
* Amount of insurance.
*/
@@ -358,6 +363,7 @@ url_handler (void *cls,
if (0 == strcmp (method,
MHD_HTTP_METHOD_POST))
{
+ // FIXME: need to accumulate upload_data first!
return AH_handler_policy_post (connection,
hc,
&account_pub,
@@ -396,6 +402,7 @@ url_handler (void *cls,
if (0 == strcmp (method,
MHD_HTTP_METHOD_POST))
{
+ // FIXME: need to accumulate upload_data first!
return AH_handler_truth_post (connection,
hc,
&tu,
@@ -442,6 +449,7 @@ do_shutdown (void *cls)
(void) cls;
AH_resume_all_bc ();
AH_truth_shutdown ();
+ AH_truth_upload_shutdown ();
if (NULL != mhd_task)
{
GNUNET_SCHEDULER_cancel (mhd_task);
@@ -639,6 +647,18 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
+ if (GNUNET_OK !=
+ TALER_config_get_amount (config,
+ "anastasis",
+ "TRUTH_UPLOAD_FEE",
+ &AH_truth_upload_fee))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "anastasis",
+ "TRUTH_UPLOAD_FEE");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
if (GNUNET_OK !=
TALER_config_get_currency (config,
&AH_currency))
@@ -679,6 +699,35 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
+ if ( (0 != strncasecmp ("https://",
+ AH_backend_url,
+ strlen ("https://"))) &&
+ (0 != strncasecmp ("http://",
+ AH_backend_url,
+ strlen ("http://"))) )
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "anastasis",
+ "PAYMENT_BACKEND_URL",
+ "Must be HTTP(S) URL");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ if ( (0 == strcasecmp ("https://",
+ AH_backend_url)) ||
+ (0 == strcasecmp ("http://",
+ AH_backend_url)) )
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "anastasis",
+ "PAYMENT_BACKEND_URL",
+ "Must have domain name");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (config,
"anastasis",
diff --git a/src/backend/anastasis-httpd.h b/src/backend/anastasis-httpd.h
index 4a98248..7384fe1 100644
--- a/src/backend/anastasis-httpd.h
+++ b/src/backend/anastasis-httpd.h
@@ -139,11 +139,14 @@ extern unsigned long long AH_upload_limit_mb;
/**
* Annual fee for the backup account.
- *
- * FIXME: the amount to pay is fixed to this value. Better variable value?
*/
extern struct TALER_Amount AH_annual_fee;
+/**
+ * Fee for a truth upload.
+ */
+extern struct TALER_Amount AH_truth_upload_fee;
+
/**
* Amount of insurance.
*/
@@ -189,6 +192,7 @@ extern struct ANASTASIS_CRYPTO_PowSalt AH_server_salt;
*/
extern struct GNUNET_CURL_Context *AH_ctx;
+
/**
* Kick MHD to run now, to be called after MHD_resume_connection().
* Basically, we need to explicitly resume MHD's event loop whenever
diff --git a/src/backend/anastasis-httpd_policy.c
b/src/backend/anastasis-httpd_policy.c
index 72e74be..4e89bb4 100644
--- a/src/backend/anastasis-httpd_policy.c
+++ b/src/backend/anastasis-httpd_policy.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2019 GNUnet e.V.
+ Copyright (C) 2019, 2021 Taler Systems SA
TALER 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
@@ -55,6 +55,7 @@ return_policy (struct MHD_Connection *connection,
struct ANASTASIS_AccountSignatureP account_sig;
struct GNUNET_HashCode recovery_data_hash;
const char *version_s;
+ char version_b[14];
uint32_t version;
void *res_recovery_data;
size_t res_recovery_data_size;
@@ -64,9 +65,12 @@ return_policy (struct MHD_Connection *connection,
"version");
if (NULL != version_s)
{
+ char dummy;
+
if (1 != sscanf (version_s,
- "%u",
- &version))
+ "%u%c",
+ &version,
+ &dummy))
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
@@ -90,7 +94,11 @@ return_policy (struct MHD_Connection *connection,
&res_recovery_data_size,
&res_recovery_data,
&version);
-
+ GNUNET_snprintf (version_b,
+ sizeof (version_b),
+ "%u",
+ (unsigned int) version);
+ version_s = version_b;
}
switch (qs)
{
@@ -99,13 +107,13 @@ return_policy (struct MHD_Connection *connection,
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
- "recovery document");
+ "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,
- NULL);
+ "get_recovery_document");
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
GNUNET_break (0);
return TALER_MHD_reply_with_error (connection,
@@ -132,6 +140,10 @@ return_policy (struct MHD_Connection *connection,
MHD_add_response_header (resp,
ANASTASIS_HTTP_HEADER_POLICY_SIGNATURE,
sig_s));
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (resp,
+
ANASTASIS_HTTP_HEADER_POLICY_VERSION,
+ version_s));
GNUNET_break (MHD_YES ==
MHD_add_response_header (resp,
MHD_HTTP_HEADER_ETAG,
diff --git a/src/backend/anastasis-httpd_policy.h
b/src/backend/anastasis-httpd_policy.h
index 6285508..9fb630d 100644
--- a/src/backend/anastasis-httpd_policy.h
+++ b/src/backend/anastasis-httpd_policy.h
@@ -45,6 +45,8 @@ AH_policy_get (struct MHD_Connection *connection,
/**
+ * Handle POST /policy/$ACCOUNT_PUB request.
+ *
* @param connection the MHD connection to handle
* @param con_cls the connection's closure
* @param account_pub public key of the account
diff --git a/src/backend/anastasis-httpd_policy_upload.c
b/src/backend/anastasis-httpd_policy_upload.c
index 744aa87..61decba 100644
--- a/src/backend/anastasis-httpd_policy_upload.c
+++ b/src/backend/anastasis-httpd_policy_upload.c
@@ -44,11 +44,6 @@
struct PolicyUploadContext
{
- /**
- * Context for cleanup logic.
- */
- struct TM_HandlerContext hc;
-
/**
* Signature of the account holder.
*/
@@ -59,22 +54,12 @@ struct PolicyUploadContext
*/
struct ANASTASIS_CRYPTO_AccountPublicKeyP account;
- /**
- * Hash of the previous upload, or zeros if first upload.
- */
- struct GNUNET_HashCode old_policy_upload_hash;
-
/**
* Hash of the upload we are receiving right now (as promised
* by the client, to be verified!).
*/
struct GNUNET_HashCode new_policy_upload_hash;
- /**
- * The claim token
- */
- struct TALER_ClaimTokenP claim_token;
-
/**
* Hash context for the upload.
*/
@@ -146,11 +131,6 @@ struct PolicyUploadContext
*/
unsigned int response_code;
- /**
- * Whether to generate a claim token.
- */
- bool make_claim_token;
-
/**
* true if client provided a payment secret / order ID?
*/
@@ -210,6 +190,8 @@ cleanup_ctx (struct TM_HandlerContext *hc)
if (NULL != puc->po)
TALER_MERCHANT_orders_post_cancel (puc->po);
+ if (NULL != puc->cpo)
+ TALER_MERCHANT_merchant_order_get_cancel (puc->cpo);
if (NULL != puc->hash_ctx)
GNUNET_CRYPTO_hash_context_abort (puc->hash_ctx);
if (NULL != puc->resp)
@@ -428,6 +410,7 @@ check_payment_cb (void *cls,
/* refunds are not supported, verify */
puc->cpo = NULL;
+ // FIXME: osr could be NULL! check hr first!
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Payment status checked: %s\n",
osr->status ? "paid" : "unpaid");
@@ -527,13 +510,10 @@ await_payment (struct PolicyUploadContext *puc,
* if required.
*
* @param puc context to begin payment for.
- * @param pay_req #GNUNET_YES if payment was explicitly requested,
- * #GNUNET_NO if payment is needed
* @return MHD status code
*/
static MHD_RESULT
-begin_payment (struct PolicyUploadContext *puc,
- int pay_req)
+begin_payment (struct PolicyUploadContext *puc)
{
json_t *order;
enum GNUNET_DB_QueryStatus qs;
@@ -618,8 +598,7 @@ prepare_payment (struct PolicyUploadContext *puc)
GNUNET_CRYPTO_QUALITY_NONCE,
&puc->payment_identifier,
sizeof (struct ANASTASIS_PaymentSecretP));
- return begin_payment (puc,
- GNUNET_NO);
+ return begin_payment (puc);
}
await_payment (puc,
CHECK_PAYMENT_GENERIC_TIMEOUT);
@@ -627,40 +606,6 @@ prepare_payment (struct PolicyUploadContext *puc)
}
-/**
- * We got some query status from the DB. Handle the error cases.
- * May perform asynchronous operations by suspending the connection
- * if required.
- *
- * @param puc connection to handle status for
- * @param qs query status to handle
- * @return #MHD_YES or #MHD_NO
- */
-static MHD_RESULT
-handle_database_error (struct PolicyUploadContext *puc,
- enum GNUNET_DB_QueryStatus qs)
-{
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- case GNUNET_DB_STATUS_SOFT_ERROR:
- GNUNET_break (0);
- return TALER_MHD_reply_with_error (puc->con,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- NULL);
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- GNUNET_assert (0);
- return MHD_NO;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- GNUNET_assert (0);
- return MHD_NO;
- }
- GNUNET_break (0);
- return MHD_NO;
-}
-
-
MHD_RESULT
AH_handler_policy_post (
struct MHD_Connection *connection,
@@ -676,7 +621,7 @@ AH_handler_policy_post (
/* first call, setup internals */
puc = GNUNET_new (struct PolicyUploadContext);
hc->ctx = puc;
- puc->hc.cc = &cleanup_ctx;
+ hc->cc = &cleanup_ctx;
puc->con = connection;
{
@@ -684,7 +629,7 @@ AH_handler_policy_post (
pay_id = MHD_lookup_connection_value (connection,
MHD_HEADER_KIND,
- "Payment-Identifier");
+
ANASTASIS_HTTP_HEADER_PAYMENT_IDENTIFIER);
if (NULL != pay_id)
{
if (GNUNET_OK !=
@@ -698,7 +643,8 @@ AH_handler_policy_post (
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "Payment-Identifier header must
be a base32-encoded Payment-Secret");
+
ANASTASIS_HTTP_HEADER_PAYMENT_IDENTIFIER
+ " header must be a base32-encoded
Payment-Secret");
}
puc->payment_identifier_provided = true;
}
@@ -722,8 +668,8 @@ AH_handler_policy_post (
connection,
MHD_HTTP_BAD_REQUEST,
(NULL == lens)
- ? TALER_EC_ANASTASIS_POLICY_MISSING_CONTENT_LENGTH
- : TALER_EC_ANASTASIS_POLICY_MALFORMED_CONTENT_LENGTH,
+ ? TALER_EC_ANASTASIS_GENERIC_MISSING_CONTENT_LENGTH
+ : TALER_EC_ANASTASIS_GENERIC_MALFORMED_CONTENT_LENGTH,
NULL);
}
if (len / 1024 / 1024 >= AH_upload_limit_mb)
@@ -795,7 +741,6 @@ AH_handler_policy_post (
struct ANASTASIS_UploadSignaturePS usp = {
.purpose.size = htonl (sizeof (usp)),
.purpose.purpose = htonl (TALER_SIGNATURE_ANASTASIS_POLICY_UPLOAD),
- // usp.old_recovery_data_hash = puc->old_policy_upload_hash,
.new_recovery_data_hash = puc->new_policy_upload_hash
};
@@ -829,8 +774,10 @@ AH_handler_policy_post (
&paid,
&valid_counter);
if (qs < 0)
- return handle_database_error (puc,
- qs);
+ return TALER_MHD_reply_with_error (puc->con,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL);
if ( (! paid) || (! valid_counter) )
{
@@ -842,8 +789,7 @@ AH_handler_policy_post (
&puc->payment_identifier,
sizeof (struct ANASTASIS_PaymentSecretP));
}
- return begin_payment (puc,
- GNUNET_YES);
+ return begin_payment (puc);
}
}
@@ -855,14 +801,12 @@ AH_handler_policy_post (
TALER_amount_get_zero (AH_currency,
&zero_amount);
/* generate fresh payment identifier */
- GNUNET_CRYPTO_random_block (
- GNUNET_CRYPTO_QUALITY_STRONG,
- &puc->payment_identifier,
- sizeof (struct ANASTASIS_PaymentSecretP));
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
+ &puc->payment_identifier,
+ sizeof (struct ANASTASIS_PaymentSecretP));
if (0 != TALER_amount_cmp (&AH_annual_fee,
&zero_amount))
- return begin_payment (puc,
- GNUNET_YES);
+ return begin_payment (puc);
/* Cost is zero, fake "zero" payment having happened */
qs = db->record_recdoc_payment (db->cls,
account_pub,
@@ -870,15 +814,19 @@ AH_handler_policy_post (
&puc->payment_identifier,
&AH_annual_fee);
if (qs <= 0)
- return handle_database_error (puc,
- qs);
+ return TALER_MHD_reply_with_error (puc->con,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL);
qs = db->increment_lifetime (db->cls,
account_pub,
&puc->payment_identifier,
GNUNET_TIME_UNIT_YEARS);
if (qs <= 0)
- return handle_database_error (puc,
- qs);
+ return TALER_MHD_reply_with_error (puc->con,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL);
}
}
@@ -890,8 +838,7 @@ AH_handler_policy_post (
MHD_GET_ARGUMENT_KIND,
"pay");
if (NULL != order_req)
- return begin_payment (puc,
- GNUNET_YES);
+ return begin_payment (puc);
}
/* Check if existing policy matches upload (and if, skip it) */
@@ -909,8 +856,10 @@ AH_handler_policy_post (
case ANASTASIS_DB_ACCOUNT_STATUS_PAYMENT_REQUIRED:
return prepare_payment (puc);
case ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR:
- return handle_database_error (puc,
- GNUNET_DB_STATUS_HARD_ERROR);
+ return TALER_MHD_reply_with_error (puc->con,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL);
case ANASTASIS_DB_ACCOUNT_STATUS_NO_RESULTS:
/* continue below */
break;
@@ -949,6 +898,24 @@ AH_handler_policy_post (
return MHD_YES;
}
+ if (NULL != puc->resp)
+ {
+ MHD_RESULT ret;
+
+ /* We generated a response asynchronously, queue that */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Returning asynchronously generated response with HTTP status
%u\n",
+ puc->response_code);
+ ret = MHD_queue_response (connection,
+ puc->response_code,
+ puc->resp);
+ GNUNET_break (MHD_YES == ret);
+ MHD_destroy_response (puc->resp);
+ puc->resp = NULL;
+ return ret;
+ }
+
+
/* handle upload */
if (0 != *recovery_data_size)
{
@@ -973,23 +940,6 @@ AH_handler_policy_post (
return MHD_YES;
}
- if (NULL != puc->resp)
- {
- MHD_RESULT ret;
-
- /* We generated a response asynchronously, queue that */
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Returning asynchronously generated response with HTTP status
%u\n",
- puc->response_code);
- ret = MHD_queue_response (connection,
- puc->response_code,
- puc->resp);
- GNUNET_break (MHD_YES == ret);
- MHD_destroy_response (puc->resp);
- puc->resp = NULL;
- return ret;
- }
-
/* finished with upload, check hash */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Upload finished\n");
@@ -1037,20 +987,18 @@ AH_handler_policy_post (
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
&puc->payment_identifier,
sizeof (struct ANASTASIS_PaymentSecretP));
- return begin_payment (puc,
- GNUNET_YES);
+ return begin_payment (puc);
case ANASTASIS_DB_STORE_STATUS_PAYMENT_REQUIRED:
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
&puc->payment_identifier,
sizeof (struct ANASTASIS_PaymentSecretP));
- return begin_payment (puc,
- GNUNET_YES);
+ return begin_payment (puc);
case ANASTASIS_DB_STORE_STATUS_HARD_ERROR:
- return handle_database_error (puc,
- GNUNET_DB_STATUS_HARD_ERROR);
case ANASTASIS_DB_STORE_STATUS_SOFT_ERROR:
- return handle_database_error (puc,
- GNUNET_DB_STATUS_SOFT_ERROR);
+ return TALER_MHD_reply_with_error (puc->con,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL);
case ANASTASIS_DB_STORE_STATUS_NO_RESULTS:
{
/* database says nothing actually changed, 304 (could
diff --git a/src/backend/anastasis-httpd_truth.c
b/src/backend/anastasis-httpd_truth.c
index ce6551d..a14eb1d 100644
--- a/src/backend/anastasis-httpd_truth.c
+++ b/src/backend/anastasis-httpd_truth.c
@@ -26,7 +26,6 @@
#include "anastasis-httpd_truth.h"
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_rest_lib.h>
-#include "anastasis_authorization_plugin.h"
#include "anastasis_authorization_lib.h"
#include <taler/taler_merchant_service.h>
#include <taler/taler_json_lib.h>
@@ -180,6 +179,16 @@ request_done (struct TM_HandlerContext *hc)
gc->authorization = NULL;
gc->as = NULL;
}
+ if (NULL != gc->cpo)
+ {
+ TALER_MERCHANT_merchant_order_get_cancel (gc->cpo);
+ gc->cpo = NULL;
+ }
+ if (NULL != gc->po)
+ {
+ TALER_MERCHANT_orders_post_cancel (gc->po);
+ gc->po = NULL;
+ }
GNUNET_free (gc);
hc->ctx = NULL;
}
diff --git a/src/backend/anastasis-httpd_truth.h
b/src/backend/anastasis-httpd_truth.h
index f523a55..7a1b95f 100644
--- a/src/backend/anastasis-httpd_truth.h
+++ b/src/backend/anastasis-httpd_truth.h
@@ -24,11 +24,24 @@
#define ANASTASIS_HTTPD_TRUTH_H
#include <microhttpd.h>
+
+/**
+ * Prepare all active GET truth requests for system shutdown.
+ */
void
AH_truth_shutdown (void);
/**
+ * Prepare all active POST truth requests for system shutdown.
+ */
+void
+AH_truth_upload_shutdown (void);
+
+
+/**
+ * Handle a GET to /truth/$UUID
+ *
* @param connection the MHD connection to handle
* @param truth_uuid the truth UUID
* @param con_cls
@@ -40,7 +53,10 @@ AH_handler_truth_get (
const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
struct TM_HandlerContext *hc);
+
/**
+ * Handle a POST to /truth/$UUID.
+ *
* @param connection the MHD connection to handle
* @param con_cls the connection's closure
* @param truth_uuid the truth UUID
diff --git a/src/backend/anastasis-httpd_truth_upload.c
b/src/backend/anastasis-httpd_truth_upload.c
index 8351745..b8b23cb 100644
--- a/src/backend/anastasis-httpd_truth_upload.c
+++ b/src/backend/anastasis-httpd_truth_upload.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2019 GNUnet e.V.
+ Copyright (C) 2019, 2021 Taler Systems SA
TALER 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
@@ -14,8 +14,8 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file anastasis-httpd_truth.c
- * @brief functions to handle incoming requests on /truth
+ * @file anastasis-httpd_truth_upload.c
+ * @brief functions to handle incoming POST request on /truth
* @author Dennis Neufeld
* @author Dominik Meister
* @author Christian Grothoff
@@ -29,31 +29,396 @@
#include <taler/taler_json_lib.h>
#include <taler/taler_merchant_service.h>
#include <taler/taler_signatures.h>
+#include "anastasis_authorization_lib.h"
+/**
+ * Information we track per truth upload.
+ */
+struct TruthUploadContext
+{
+
+ /**
+ * UUID of the truth object we are processing.
+ */
+ struct ANASTASIS_CRYPTO_TruthUUIDP truth_uuid;
+
+ /**
+ * Kept in DLL for shutdown handling while suspended.
+ */
+ struct TruthUploadContext *next;
+
+ /**
+ * Kept in DLL for shutdown handling while suspended.
+ */
+ struct TruthUploadContext *prev;
+
+ /**
+ * Used while we are awaiting proposal creation.
+ */
+ struct TALER_MERCHANT_PostOrdersHandle *po;
+
+ /**
+ * Used while we are waiting payment.
+ */
+ struct TALER_MERCHANT_OrderMerchantGetHandle *cpo;
+
+ /**
+ * Post parser context.
+ */
+ void *post_ctx;
+
+ /**
+ * Handle to the client request.
+ */
+ struct MHD_Connection *connection;
+
+ /**
+ * HTTP response code to use on resume, if non-NULL.
+ */
+ struct MHD_Response *resp;
+
+ /**
+ * HTTP response code to use on resume, if resp is set.
+ */
+ unsigned int response_code;
+
+};
+
+
+/**
+ * Head of linked list over all truth upload processes
+ */
+static struct TruthUploadContext *tuc_head;
+
+/**
+ * Tail of linked list over all truth upload processes
+ */
+static struct TruthUploadContext *tuc_tail;
+
+
+void
+AH_truth_upload_shutdown (void)
+{
+ struct TruthUploadContext *tuc;
+
+ while (NULL != (tuc = tuc_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (tuc_head,
+ tuc_tail,
+ tuc);
+ MHD_resume_connection (tuc->connection);
+ }
+}
+
+
+/**
+ * Function called to clean up a `struct TruthUploadContext`.
+ *
+ * @param hc general handler context
+ */
+static void
+cleanup_truth_post (struct TM_HandlerContext *hc)
+{
+ struct TruthUploadContext *tuc = hc->ctx;
+
+ TALER_MHD_parse_post_cleanup_callback (tuc->post_ctx);
+ if (NULL != tuc->po)
+ TALER_MERCHANT_orders_post_cancel (tuc->po);
+ if (NULL != tuc->cpo)
+ TALER_MERCHANT_merchant_order_get_cancel (tuc->cpo);
+ if (NULL != tuc->resp)
+ MHD_destroy_response (tuc->resp);
+ GNUNET_free (tuc);
+}
+
+
+/**
+ * Transmit a payment request for @a tuc.
+ *
+ * @param tuc upload context to generate payment request for
+ */
+static void
+make_payment_request (struct TruthUploadContext *tuc)
+{
+ struct MHD_Response *resp;
+
+ /* request payment via Taler */
+ resp = MHD_create_response_from_buffer (0,
+ NULL,
+ MHD_RESPMEM_PERSISTENT);
+ GNUNET_assert (NULL != resp);
+ TALER_MHD_add_global_headers (resp);
+ {
+ char *hdr;
+ char *pfx;
+ char *hn;
+
+ if (0 == strncasecmp ("https://",
+ AH_backend_url,
+ strlen ("https://")))
+ {
+ pfx = "taler://";
+ hn = &AH_backend_url[strlen ("https://")];
+ }
+ else if (0 == strncasecmp ("http://",
+ AH_backend_url,
+ strlen ("http://")))
+ {
+ pfx = "taler+http://";
+ hn = &AH_backend_url[strlen ("http://")];
+ }
+ else
+ {
+ /* This invariant holds as per check in anastasis-httpd.c */
+ GNUNET_assert (0);
+ }
+ /* This invariant holds as per check in anastasis-httpd.c */
+ GNUNET_assert (0 != strlen (hn));
+ {
+ char *order_id;
+
+ order_id = GNUNET_STRINGS_data_to_string_alloc (
+ &tuc->truth_uuid,
+ sizeof (tuc->truth_uuid));
+ GNUNET_asprintf (&hdr,
+ "%spay/%s%s/",
+ pfx,
+ hn,
+ order_id);
+ GNUNET_free (order_id);
+ }
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (resp,
+ ANASTASIS_HTTP_HEADER_TALER,
+ hdr));
+ GNUNET_free (hdr);
+ }
+ tuc->resp = resp;
+ tuc->response_code = MHD_HTTP_PAYMENT_REQUIRED;
+}
+
+
+/**
+ * Callbacks of this type are used to serve the result of submitting a
+ * POST /private/orders request to a merchant.
+ *
+ * @param cls our `struct TruthUploadContext`
+ * @param por response details
+ */
+static void
+proposal_cb (void *cls,
+ const struct TALER_MERCHANT_PostOrdersReply *por)
+{
+ struct TruthUploadContext *tuc = cls;
+
+ tuc->po = NULL;
+ GNUNET_CONTAINER_DLL_remove (tuc_head,
+ tuc_tail,
+ tuc);
+ MHD_resume_connection (tuc->connection);
+ AH_trigger_daemon (NULL);
+ if (MHD_HTTP_OK != por->hr.http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Backend returned status %u/%d\n",
+ por->hr.http_status,
+ (int) por->hr.ec);
+ GNUNET_break (0);
+ tuc->resp = TALER_MHD_make_json_pack (
+ "{s:I, s:s, s:I, s:I, s:O?}",
+ "code",
+ (json_int_t) TALER_EC_ANASTASIS_GENERIC_ORDER_CREATE_BACKEND_ERROR,
+ "hint",
+ "Failed to setup order with merchant backend",
+ "backend-ec",
+ (json_int_t) por->hr.ec,
+ "backend-http-status",
+ (json_int_t) por->hr.http_status,
+ "backend-reply",
+ por->hr.reply);
+ GNUNET_assert (NULL != tuc->resp);
+ tuc->response_code = MHD_HTTP_BAD_GATEWAY;
+ return;
+ }
+ make_payment_request (tuc);
+}
+
+
+/**
+ * Callback to process a GET /check-payment request
+ *
+ * @param cls our `struct PolicyUploadContext`
+ * @param hr HTTP response details
+ * @param osr order status
+ */
static void
-cleanup_parse_post_json (struct TM_HandlerContext *hc)
+check_payment_cb (void *cls,
+ const struct TALER_MERCHANT_HttpResponse *hr,
+ const struct TALER_MERCHANT_OrderStatusResponse *osr)
{
- TALER_MHD_parse_post_cleanup_callback (hc->ctx);
+ struct TruthUploadContext *tuc = cls;
+
+ tuc->cpo = NULL;
+ switch (hr->http_status)
+ {
+ case 0:
+ /* Likely timeout, complain! */
+ tuc->response_code = MHD_HTTP_GATEWAY_TIMEOUT;
+ tuc->resp = TALER_MHD_make_error (
+ TALER_EC_ANASTASIS_GENERIC_BACKEND_TIMEOUT,
+ NULL);
+ break;
+ case MHD_HTTP_OK:
+ switch (osr->status)
+ {
+ case TALER_MERCHANT_OSC_PAID:
+ {
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = db->record_truth_upload_payment (db->cls,
+ &tuc->truth_uuid,
+ &AH_truth_upload_fee,
+ GNUNET_TIME_UNIT_YEARS);
+ if (qs <= 0)
+ {
+ tuc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ tuc->resp = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
+ "record_truth_upload_payment");
+ break;
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Payment confirmed, resuming upload\n");
+ break;
+ case TALER_MERCHANT_OSC_UNPAID:
+ case TALER_MERCHANT_OSC_CLAIMED:
+ make_payment_request (tuc);
+ break;
+ }
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ /* Configuration issue, complain! */
+ tuc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ tuc->resp = TALER_MHD_make_json_pack (
+ "{s:I, s:s, s:I, s:I, s:O?}",
+ "code",
+ (json_int_t) TALER_EC_ANASTASIS_GENERIC_PAYMENT_CHECK_UNAUTHORIZED,
+ "hint",
+ TALER_ErrorCode_get_hint (
+ TALER_EC_ANASTASIS_GENERIC_PAYMENT_CHECK_UNAUTHORIZED),
+ "backend-ec",
+ (json_int_t) hr->ec,
+ "backend-http-status",
+ (json_int_t) hr->http_status,
+ "backend-reply",
+ hr->reply);
+ GNUNET_assert (NULL != tuc->resp);
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* Setup fresh order */
+ {
+ char *order_id;
+ json_t *order;
+
+ order_id = GNUNET_STRINGS_data_to_string_alloc (
+ &tuc->truth_uuid,
+ sizeof(tuc->truth_uuid));
+ order = json_pack ("{s:o, s:s, s:s, s:s}",
+ "amount",
+ TALER_JSON_from_amount (&AH_truth_upload_fee),
+ "summary",
+ "Anastasis challenge storage fee",
+ "order_id",
+ order_id);
+ GNUNET_free (order_id);
+ tuc->po = TALER_MERCHANT_orders_post2 (AH_ctx,
+ AH_backend_url,
+ order,
+ GNUNET_TIME_UNIT_ZERO,
+ NULL, /* no payment target */
+ 0,
+ NULL, /* no inventory products */
+ 0,
+ NULL, /* no uuids */
+ false, /* do NOT require claim
token */
+ &proposal_cb,
+ tuc);
+ AH_trigger_curl ();
+ json_decref (order);
+ return;
+ }
+ default:
+ /* Unexpected backend response */
+ tuc->response_code = MHD_HTTP_BAD_GATEWAY;
+ tuc->resp = TALER_MHD_make_json_pack (
+ "{s:I, s:s, s:I, s:I, s:O?}",
+ "code",
+ (json_int_t) TALER_EC_ANASTASIS_GENERIC_BACKEND_ERROR,
+ "hint",
+ TALER_ErrorCode_get_hint (TALER_EC_ANASTASIS_GENERIC_BACKEND_ERROR),
+ "backend-ec",
+ (json_int_t) hr->ec,
+ "backend-http-status",
+ (json_int_t) hr->http_status,
+ "backend-reply",
+ hr->reply);
+ break;
+ }
+ GNUNET_CONTAINER_DLL_remove (tuc_head,
+ tuc_tail,
+ tuc);
+ MHD_resume_connection (tuc->connection);
+ AH_trigger_daemon (NULL);
}
/**
- * @param connection the MHD connection to handle
- * @param con_cls the connection's closure
- * @param pub_key_str base32 encoded truth public key
- * @param truth_data truth data
- * @param truth_data_size number of bytes (left) in @a truth_data
- * @return MHD result code
+ * Helper function used to ask our backend to begin processing a
+ * payment for the truth upload. May perform asynchronous operations
+ * by suspending the connection if required.
+ *
+ * @param tuc context to begin payment for.
+ * @return MHD status code
*/
+static MHD_RESULT
+begin_payment (struct TruthUploadContext *tuc)
+{
+ char *order_id;
+
+ order_id = GNUNET_STRINGS_data_to_string_alloc (
+ &tuc->truth_uuid,
+ sizeof (tuc->truth_uuid));
+ tuc->cpo = TALER_MERCHANT_merchant_order_get (AH_ctx,
+ AH_backend_url,
+ order_id,
+ NULL /* our payments are NOT
session-bound */,
+ false,
+ GNUNET_TIME_UNIT_SECONDS,
+ &check_payment_cb,
+ tuc);
+ GNUNET_free (order_id);
+ if (NULL == tuc->cpo)
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (tuc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+
TALER_EC_ANASTASIS_GENERIC_PAYMENT_CHECK_START_FAILED,
+ "Could not check order status");
+ }
+ return MHD_YES;
+}
+
+
int
AH_handler_truth_post (
struct MHD_Connection *connection,
struct TM_HandlerContext *hc,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_public_key,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
const char *truth_data,
size_t *truth_data_size)
{
+ struct TruthUploadContext *tuc = hc->ctx;
json_t *json;
MHD_RESULT ret;
int res;
@@ -62,17 +427,102 @@ AH_handler_truth_post (
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("keyshare_data",
&truth.keyshare_data),
- GNUNET_JSON_spec_string ("method", &truth.method),
+ GNUNET_JSON_spec_string ("method",
+ &truth.method),
GNUNET_JSON_spec_varsize ("encrypted_truth",
&truth.encrypted_truth,
&truth.encrypted_truth_size),
- GNUNET_JSON_spec_string ("truth_mime", &truth.truth_mime),
+ GNUNET_JSON_spec_string ("truth_mime",
+ &truth.truth_mime),
GNUNET_JSON_spec_end ()
};
- hc->cc = &cleanup_parse_post_json;
+ if (NULL == tuc)
+ {
+ tuc = GNUNET_new (struct TruthUploadContext);
+ tuc->connection = connection;
+ tuc->truth_uuid = *truth_uuid;
+ hc->ctx = tuc;
+ hc->cc = &cleanup_truth_post;
+
+ /* check for excessive upload */
+ {
+ const char *lens;
+ unsigned long len;
+
+ lens = MHD_lookup_connection_value (connection,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_CONTENT_LENGTH);
+ if ( (NULL == lens) ||
+ (1 != sscanf (lens,
+ "%lu",
+ &len)) )
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_BAD_REQUEST,
+ (NULL == lens)
+ ? TALER_EC_ANASTASIS_GENERIC_MISSING_CONTENT_LENGTH
+ : TALER_EC_ANASTASIS_GENERIC_MALFORMED_CONTENT_LENGTH,
+ NULL);
+ }
+ if (len / 1024 / 1024 >= AH_upload_limit_mb)
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_PAYLOAD_TOO_LARGE,
+
TALER_EC_SYNC_MALFORMED_CONTENT_LENGTH,
+ "Content-length value not
acceptable");
+ }
+ }
+
+ {
+ struct TALER_Amount zero_amount;
+
+ TALER_amount_get_zero (AH_currency,
+ &zero_amount);
+ if (0 != TALER_amount_cmp (&AH_truth_upload_fee,
+ &zero_amount))
+ {
+ struct GNUNET_TIME_Absolute paid_until;
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = db->check_truth_upload_paid (db->cls,
+ truth_uuid,
+ &paid_until);
+ if (qs < 0)
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL);
+ if ( (0 == qs) ||
+ (0 ==
+ GNUNET_TIME_absolute_get_remaining (paid_until).rel_value_us) )
+ return begin_payment (tuc);
+ }
+ }
+ } /* end 'if (NULL == tuc)' */
+
+ if (NULL != tuc->resp)
+ {
+ MHD_RESULT ret;
+
+ /* We generated a response asynchronously, queue that */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Returning asynchronously generated response with HTTP status
%u\n",
+ tuc->response_code);
+ ret = MHD_queue_response (connection,
+ tuc->response_code,
+ tuc->resp);
+ GNUNET_break (MHD_YES == ret);
+ MHD_destroy_response (tuc->resp);
+ tuc->resp = NULL;
+ return ret;
+ }
+
res = TALER_MHD_parse_post_json (connection,
- &hc->ctx,
+ &tuc->post_ctx,
truth_data,
truth_data_size,
&json);
@@ -84,13 +534,31 @@ AH_handler_truth_post (
res = TALER_MHD_parse_json_data (connection,
json,
spec);
-
if (GNUNET_SYSERR == res)
return MHD_NO; /* hard failure */
if (GNUNET_NO == res)
return MHD_YES; /* failure */
+
+ /* check method is supported */
+ {
+ struct TALER_Amount dummy;
+
+ if ( (0 != strcmp ("question",
+ truth.method)) &&
+ (NULL ==
+ ANASTASIS_authorization_plugin_load (truth.method,
+ AH_cfg,
+ &dummy)) )
+ {
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+
TALER_EC_ANASTASIS_TRUTH_UPLOAD_METHOD_NOT_SUPPORTED,
+ truth.method);
+ }
+ }
+
qs = db->store_truth (db->cls,
- truth_public_key,
+ truth_uuid,
&truth.keyshare_data,
truth.truth_mime,
truth.encrypted_truth,
@@ -99,24 +567,35 @@ AH_handler_truth_post (
AH_truth_expiration);
json_decref (json);
GNUNET_JSON_parse_free (spec);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ switch (qs)
{
- struct MHD_Response *resp;
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ 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_INVARIANT_FAILURE,
+ "store_truth");
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_CONFLICT,
+
TALER_EC_ANASTASIS_TRUTH_UPLOAD_UUID_EXISTS,
+ NULL);
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ {
+ struct MHD_Response *resp;
- resp = MHD_create_response_from_buffer (0,
- NULL,
- MHD_RESPMEM_PERSISTENT);
- TALER_MHD_add_global_headers (resp);
- ret = MHD_queue_response (connection,
- MHD_HTTP_NO_CONTENT,
- resp);
- MHD_destroy_response (resp);
- return ret;
+ resp = MHD_create_response_from_buffer (0,
+ NULL,
+ MHD_RESPMEM_PERSISTENT);
+ TALER_MHD_add_global_headers (resp);
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_NO_CONTENT,
+ resp);
+ MHD_destroy_response (resp);
+ return ret;
+ }
}
GNUNET_break (0);
- // FIXME: probably should consider 'qs' values in more detail here...
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
- "database failure");
+ return MHD_NO;
}
diff --git a/src/include/anastasis.h b/src/include/anastasis.h
index cd9b0aa..93a6921 100644
--- a/src/include/anastasis.h
+++ b/src/include/anastasis.h
@@ -38,178 +38,6 @@
struct ANASTASIS_Challenge;
-/**
- * Defines a Decryption Policy with multiple escrow methods
-*/
-struct ANASTASIS_DecryptionPolicy
-{
- /**
- * Set of truths identfied by UUID
- */
- struct ANASTASIS_CRYPTO_TruthUUIDP *uuids;
-
- /**
- * length of the @a uuids in this policy
- */
- uint32_t uuids_length;
-
- /**
- * encrypted masterkey ( encrypted with the policy key)
- */
- struct ANASTASIS_CRYPTO_EncryptedMasterKeyP emk;
-
- /**
- * salt used to decrypt master key
- */
- struct ANASTASIS_CRYPTO_SaltP salt;
-};
-
-
-/**
- * Defines the recovery information (possible policies and version of the
recovery document)
- */
-struct ANASTASIS_RecoveryInformation
-{
- // FIXME: document
- struct ANASTASIS_CRYPTO_SaltP salt;
-
- // FIXME: document
- struct ANASTASIS_DecryptionPolicy *dps;
-
- // FIXME: document
- struct ANASTASIS_Challenge **cs;
-
- // FIXME: document
- unsigned int dps_len;
-
- // FIXME: document
- unsigned int cs_len;
-
- /**
- * Actual version obtained. FIXME: of what?
- */
- unsigned int version;
-};
-
-
-/**
- * Possible outcomes of a recovery process.
- */
-enum ANASTASIS_RecoveryStatus
-{
-
- /**
- * Recovery succeeded.
- */
- ANASTASIS_RS_SUCCESS = 0,
-
- /**
- * The HTTP download of the policy failed.
- */
- ANASTASIS_RS_POLICY_DOWNLOAD_FAILED,
-
- /**
- * We did not get a valid policy document.
- */
- ANASTASIS_RS_POLICY_DOWNLOAD_NO_POLICY,
-
- /**
- * The decompressed policy document was too big for available memory.
- */
- ANASTASIS_RS_POLICY_DOWNLOAD_TOO_BIG,
-
- /**
- * The decrypted policy document was not compressed.
- */
- ANASTASIS_RS_POLICY_DOWNLOAD_INVALID_COMPRESSION,
-
- /**
- * The decompressed policy document was not in JSON.
- */
- ANASTASIS_RS_POLICY_DOWNLOAD_NO_JSON,
-
- /**
- * The decompressed policy document was in malformed JSON.
- */
- ANASTASIS_RS_POLICY_MALFORMED_JSON,
-};
-
-
-/**
- * This function is called whenever the recovery process ends.
- * On success, the secret is returned in @a secret.
- *
- * @param cls handle for the callback
- * @param ec error code
- * @param secret contains the core secret which is passed to the user
- * @param secret_size defines the size of the core secret
- */
-typedef void
-(*ANASTASIS_CoreSecretCallback)(void *cls,
- enum ANASTASIS_RecoveryStatus rc,
- const void *secret,
- size_t secret_size);
-
-/**
- * The answer feedback defines the callback for an escrow challenge e.g.
(wrong SMS Pin)
- *
- * @param af_cls handle for the callback
- * @param http_status_code status code
- * @param ec enum with the different possible states like wrong pin, success
- */
-typedef void
-(*ANASTASIS_AnswerFeedback)(void *af_cls,
- unsigned int http_status_code,
- enum TALER_ErrorCode ec);
-
-
-/**
- * Handle to a challenge answer operation.
- */
-struct ANASTASIS_ChallengeAnswerOperation;
-
-/**
- * Cancel a challenge answer operation.
- *
- * @param c the challenge for which to cancel the answer operation
- */
-void
-ANASTASIS_challenge_answer_cancel (
- struct ANASTASIS_Challenge *c);
-
-
-/**
- * Challenge answer from the user like input SMS pin. Is referenced to a
challenge and
- * sends back an AnswerFeedback.
- *
- * @param c reference to the challenge which is answered
- * @param payment_secret information about payment made for the recovery
- * @param answer user input instruction defines which input is needed
- * @param af reference to the answerfeedback which is passed back to the user
- * @param af_cls handle for the challenge answer struct
- * @return #GNUNET_OK on success
- */
-int
-ANASTASIS_challenge_answer (
- struct ANASTASIS_Challenge *c,
- const struct ANASTASIS_PaymentSecretP *payment_secret,
- const char *answer,
- ANASTASIS_AnswerFeedback af,
- void *af_cls);
-
-
-/**
- * Defines a Challenge Callback which is initially sent with the challenge
run. It gives back the previously
- * defined Challenge Information and a Status Code, like "payment missing".
- *
- * @param cls handle for the callback
- * @param ec enum which defines the different status codes
- *
-*/
-typedef void
-(*ANASTASIS_ChallengeCallback)(void *cls,
- enum TALER_ErrorCode ec); // i.e. payment
missing
-
/**
* Defines the instructions for a challenge, what does the user have
* to do to fulfill the challenge. Also defines the method and other
@@ -232,21 +60,22 @@ struct ANASTASIS_ChallengeInformation
/**
* Which method is this challenge (E-Mail, Security Question, SMS...)
*/
- char *method;
+ const char *method;
/**
* Instructions for solving the challenge (generic, set client-side
* when challenge was established).
*/
- char *instructions;
+ const char *instructions;
/**
* Defines the url or mail address used for the challenge. Can be NULL.
+ * // FIXME: is this really available? Where does this come from? is it an
URL!?
*/
- char *url;
+ // const char *url;
/**
- * true if solved, else false.
+ * true if challenged was already solved, else false.
*/
bool solved;
@@ -254,13 +83,13 @@ struct ANASTASIS_ChallengeInformation
/**
- * Returns information of a challenge.
+ * Returns detailed information about a challenge.
*
* @param challenge reference to the escrow challenge which is started
* @return ANASTASIS_ChallengeInformation object
*/
const struct ANASTASIS_ChallengeInformation *
-ANASTASIS_get_challenge (struct ANASTASIS_Challenge *challenge);
+ANASTASIS_challenge_get_details (struct ANASTASIS_Challenge *challenge);
/**
@@ -268,8 +97,16 @@ ANASTASIS_get_challenge (struct ANASTASIS_Challenge
*challenge);
*/
enum ANASTASIS_ChallengeStatus
{
+
/**
- * Instructions for how to solve the challenge are provided.
+ * The challenge has been solved.
+ */
+ ANASTASIS_CHALLENGE_STATUS_SOLVED,
+
+ /**
+ * Instructions for how to solve the challenge are provided. Also
+ * used if the answer we provided was wrong (or if no answer was
+ * provided, but one is needed).
*/
ANASTASIS_CHALLENGE_STATUS_INSTRUCTIONS,
@@ -281,7 +118,8 @@ enum ANASTASIS_ChallengeStatus
/**
* We encountered an error talking to the Anastasis service.
*/
- ANASTASIS_CHALLENGE_STATUS_SERVER_FAILURE
+ ANASTASIS_CHALLENGE_STATUS_SERVER_FAILURE,
+
};
@@ -290,19 +128,27 @@ enum ANASTASIS_ChallengeStatus
*/
struct ANASTASIS_ChallengeStartResponse
{
+ /**
+ * What is our status on satisfying this challenge. Determines @e details.
+ */
enum ANASTASIS_ChallengeStatus cs;
+ /**
+ * Which challenge is this about?
+ */
+ const struct ANASTASIS_Challenge *challenge;
+
union
{
/**
* Response with server-side instructions for the user, if
- * @e cs is ANASTASIS_CHALLENGE_STATUS_INSTRUCTIONS.
+ * @e cs is #ANASTASIS_CHALLENGE_STATUS_INSTRUCTIONS.
*/
const char *instructions;
/**
* Response with instructions for how to pay, if
- * @a cs is ANASTASIS_CHALLENGE_STATUS_PAYMENT_REQUIRED.
+ * @e cs is #ANASTASIS_CHALLENGE_STATUS_PAYMENT_REQUIRED.
*/
struct
{
@@ -319,6 +165,11 @@ struct ANASTASIS_ChallengeStartResponse
} payment_required;
+
+ /**
+ * Response with details about a server-side failure, if
+ * @e cs is #ANASTASIS_CHALLENGE_STATUS_SERVER_FAILURE.
+ */
struct
{
@@ -332,6 +183,11 @@ struct ANASTASIS_ChallengeStartResponse
*/
unsigned int http_status;
+ /**
+ * Taler-specific error code.
+ */
+ enum TALER_ErrorCode ec;
+
} server_failure;
} details;
@@ -346,9 +202,9 @@ struct ANASTASIS_ChallengeStartResponse
* @param csr response details
*/
typedef void
-(*ANASTASIS_ChallengeStartCallback)(void *cls,
- const struct
- ANASTASIS_ChallengeStartResponse *csr);
+(*ANASTASIS_AnswerFeedback)(
+ void *cls,
+ const struct ANASTASIS_ChallengeStartResponse *csr);
/**
@@ -360,19 +216,62 @@ typedef void
*
* @param c reference to the escrow challenge which is started
* @param psp payment secret, NULL if no payment was yet made
- * @param cc opens a ChallengePaymentCallback for the requested information
- * @param cc_cls handle for the request
+ * @param hashed_answer answer to the challenge, NULL if we have none yet
+ * @param af reference to the answerfeedback which is passed back to the user
+ * @param af_cls closure for @a af
* @return #GNUNET_OK if the challenge was successfully started
*/
int
ANASTASIS_challenge_start (struct ANASTASIS_Challenge *c,
const struct ANASTASIS_PaymentSecretP *psp,
- ANASTASIS_ChallengeStartCallback csc,
- void *csc_cls);
+ const struct GNUNET_HashCode *hashed_answer,
+ ANASTASIS_AnswerFeedback af,
+ void *af_cls);
/**
- * Abort challenge.
+ * Challenge answer from the user like input SMS pin. Is referenced to
+ * a challenge and sends back an AnswerFeedback. Convenience
+ * wrapper around #ANASTASIS_challenge_start that hashes @a answer.
+ *
+ * @param c reference to the challenge which is answered
+ * @param psp information about payment made for the recovery
+ * @param answer user input instruction defines which input is needed
+ * @param af reference to the answerfeedback which is passed back to the user
+ * @param af_cls closure for @a af
+ * @return #GNUNET_OK on success
+ */
+int
+ANASTASIS_challenge_answer (struct ANASTASIS_Challenge *c,
+ const struct ANASTASIS_PaymentSecretP *psp,
+ const char *answer,
+ ANASTASIS_AnswerFeedback af,
+ void *af_cls);
+
+
+/**
+ * Challenge answer from the user like input SMS pin. Is referenced to
+ * a challenge and sends back an AnswerFeedback. Convenience
+ * wrapper around #ANASTASIS_challenge_start that hashes @a answer.
+ * Variant for numeric answers.
+ *
+ * @param c reference to the challenge which is answered
+ * @param psp information about payment made for the recovery
+ * @param answer user input instruction defines which input is needed
+ * @param af reference to the answerfeedback which is passed back to the user
+ * @param af_cls closure for @a af
+ * @return #GNUNET_OK on success
+ */
+int
+ANASTASIS_challenge_answer2 (struct ANASTASIS_Challenge *c,
+ const struct ANASTASIS_PaymentSecretP *psp,
+ uint64_t answer,
+ ANASTASIS_AnswerFeedback af,
+ void *af_cls);
+
+
+/**
+ * Abort answering challenge.
*
* @param c reference to the escrow challenge which was started
*/
@@ -380,6 +279,70 @@ void
ANASTASIS_challenge_abort (struct ANASTASIS_Challenge *c);
+/**
+ * Defines a Decryption Policy with multiple escrow methods
+ */
+struct ANASTASIS_DecryptionPolicy
+{
+ /**
+ * Set of truths identfied by UUID
+ */
+ struct ANASTASIS_CRYPTO_TruthUUIDP *uuids;
+
+ /**
+ * length of the @a uuids in this policy
+ */
+ uint32_t uuids_length;
+
+ /**
+ * Encrypted masterkey (encrypted with the policy key).
+ * FIXME: why exposed to the client?
+ */
+ // struct ANASTASIS_CRYPTO_EncryptedMasterKeyP emk;
+
+ /**
+ * Salt used to decrypt master key.
+ * FIXME: why exposed to the client?
+ */
+ // struct ANASTASIS_CRYPTO_SaltP salt;
+};
+
+
+/**
+ * Defines the recovery information (possible policies and version of the
recovery document)
+ */
+struct ANASTASIS_RecoveryInformation
+{
+ // FIXME: document. Why is this exposed to the client!??
+ // struct ANASTASIS_CRYPTO_SaltP salt;
+
+ /**
+ * Array of @e dps_len policies that would allow recovery of the core secret.
+ */
+ struct ANASTASIS_DecryptionPolicy *dps;
+
+ /**
+ * Array of @e cs_len challenges to be solved (for any of the policies).
+ */
+ struct ANASTASIS_Challenge **cs;
+
+ /**
+ * Length of the @e dps array.
+ */
+ unsigned int dps_len;
+
+ /**
+ * Length of the @e cs array.
+ */
+ unsigned int cs_len;
+
+ /**
+ * Actual recovery document version obtained.
+ */
+ unsigned int version;
+};
+
+
/**
* Callback which passes back the recovery document and its possible
* policies. Also passes back the version of the document for the user
@@ -393,6 +356,65 @@ typedef void
const struct ANASTASIS_RecoveryInformation *ri);
+/**
+ * Possible outcomes of a recovery process.
+ */
+enum ANASTASIS_RecoveryStatus
+{
+
+ /**
+ * Recovery succeeded.
+ */
+ ANASTASIS_RS_SUCCESS = 0,
+
+ /**
+ * The HTTP download of the policy failed.
+ */
+ ANASTASIS_RS_POLICY_DOWNLOAD_FAILED,
+
+ /**
+ * We did not get a valid policy document.
+ */
+ ANASTASIS_RS_POLICY_DOWNLOAD_NO_POLICY,
+
+ /**
+ * The decompressed policy document was too big for available memory.
+ */
+ ANASTASIS_RS_POLICY_DOWNLOAD_TOO_BIG,
+
+ /**
+ * The decrypted policy document was not compressed.
+ */
+ ANASTASIS_RS_POLICY_DOWNLOAD_INVALID_COMPRESSION,
+
+ /**
+ * The decompressed policy document was not in JSON.
+ */
+ ANASTASIS_RS_POLICY_DOWNLOAD_NO_JSON,
+
+ /**
+ * The decompressed policy document was in malformed JSON.
+ */
+ ANASTASIS_RS_POLICY_MALFORMED_JSON,
+};
+
+
+/**
+ * This function is called whenever the recovery process ends.
+ * On success, the secret is returned in @a secret.
+ *
+ * @param cls handle for the callback
+ * @param ec error code
+ * @param secret contains the core secret which is passed to the user
+ * @param secret_size defines the size of the core secret
+ */
+typedef void
+(*ANASTASIS_CoreSecretCallback)(void *cls,
+ enum ANASTASIS_RecoveryStatus rc,
+ const void *secret,
+ size_t secret_size);
+
+
/**
* stores provider URIs, identity key material, decrypted recovery document
(internally!)
*/
@@ -435,13 +457,6 @@ ANASTASIS_recovery_abort (struct ANASTASIS_Recovery *r);
/* ************************* Backup API ***************************** */
-/**
- * Handle for the operation to establish a truth object by sharing
- * an encrypted key share with an Anastasis provider.
- */
-struct ANASTASIS_TruthUpload;
-
-
/**
* Represents a truth object, which is a key share and the respective
* challenge to be solved with an Anastasis provider to recover the
@@ -450,6 +465,38 @@ struct ANASTASIS_TruthUpload;
struct ANASTASIS_Truth;
+/**
+ * Extracts truth data from JSON.
+ *
+ * @param json JSON encoding to decode; truth returned ONLY valid as long
+ * as the JSON remains valid (do not decref until the truth
+ * is truly finished)
+ * @return decoded truth object, NULL on error
+ */
+struct ANASTASIS_Truth *
+ANASTASIS_truth_from_json (const json_t *json);
+
+
+/**
+ * Returns JSON-encoded truth data.
+ * Creates a policy with a set of truth's. Creates the policy key
+ * with the different key shares from the @a truths. The policy key
+ * will then be used to encrypt/decrypt the escrow master key.
+ *
+ * @param t object to return JSON encoding for
+ * @return JSON encoding of @a t
+ */
+json_t *
+ANASTASIS_truth_to_json (const struct ANASTASIS_Truth *t);
+
+
+/**
+ * Handle for the operation to establish a truth object by sharing
+ * an encrypted key share with an Anastasis provider.
+ */
+struct ANASTASIS_TruthUpload;
+
+
/**
* Upload result information. The resulting truth object can be used
* to create policies. If payment is required, the @a taler_pay_url
@@ -570,8 +617,19 @@ struct ANASTASIS_SharePaymentRequest
*/
enum ANASTASIS_ShareStatus
{
+ /**
+ * Upload successful.
+ */
ANASTASIS_SHARE_STATUS_SUCCESS = 0,
+
+ /**
+ * Upload requires payment.
+ */
ANASTASIS_SHARE_STATUS_PAYMENT_REQUIRED,
+
+ /**
+ * Failure to upload secret share at the provider.
+ */
ANASTASIS_SHARE_STATUS_PROVIDER_FAILED
};
diff --git a/src/include/anastasis_database_plugin.h
b/src/include/anastasis_database_plugin.h
index 50d8eb6..ab29c78 100644
--- a/src/include/anastasis_database_plugin.h
+++ b/src/include/anastasis_database_plugin.h
@@ -500,6 +500,38 @@ struct ANASTASIS_DatabasePlugin
const struct TALER_Amount *amount);
+ /**
+ * Record truth upload payment was made.
+ *
+ * @param cls closure
+ * @param uuid the truth's UUID
+ * @param amount the amount that was paid
+ * @param duration how long is the truth paid for
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*record_truth_upload_payment)(
+ void *cls,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid,
+ const struct TALER_Amount *amount,
+ struct GNUNET_TIME_Relative duration);
+
+
+ /**
+ * Inquire whether truth upload payment was made.
+ *
+ * @param cls closure
+ * @param uuid the truth's UUID
+ * @param[out] paid_until set for how long this truth is paid for
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*check_truth_upload_paid)(
+ void *cls,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid,
+ struct GNUNET_TIME_Absolute *paid_until);
+
+
/**
* Verify the provided code with the code on the server.
* If the code matches the function will return with success, if the code
diff --git a/src/include/anastasis_service.h b/src/include/anastasis_service.h
index 35f526f..173eb1f 100644
--- a/src/include/anastasis_service.h
+++ b/src/include/anastasis_service.h
@@ -287,30 +287,8 @@ struct ANASTASIS_UploadDetails
const struct GNUNET_HashCode *curr_backup_hash;
/**
- * Previous backup. Returned if @e us is
- * #ANASTASIS_US_CONFLICTING_POLICY
+ * Details about required payment.
*/
- struct
- {
- /**
- * Hash over @e existing_backup.
- */
- struct GNUNET_HashCode existing_backup_hash;
-
- /**
- * Number of bytes in @e existing_backup.
- */
- size_t existing_backup_size;
-
- /**
- * The backup on the server, which does not match the
- * "previous" backup expected by the client and thus
- * needs to be decrypted, reconciled and re-uploaded.
- */
- const void *existing_backup;
-
- } recovered_backup;
-
struct
{
/**
@@ -342,7 +320,7 @@ typedef void
/**
- * Store policies, does a POST /policy/$AccountPub
+ * Store policies, does a POST /policy/$ACCOUNT_PUB
*
* @param ctx the CURL context used to connect to the backend
* @param backend_url backend's base URL, including final "/"
@@ -381,20 +359,146 @@ ANASTASIS_policy_store_cancel (
/****** TRUTH API ******/
+/**
+ * Operational status.
+ */
+enum ANASTASIS_KeyShareDownloadStatus
+{
+ /**
+ * We got the encrypted key share.
+ */
+ ANASTASIS_KSD_SUCCESS = 0,
+
+ /**
+ * Payment is needed to proceed with the recovery.
+ */
+ ANASTASIS_KSD_PAYMENT_REQUIRED,
+
+ /**
+ * The provided answer was wrong or missing. Instructions for
+ * getting a good answer may be provided.
+ */
+ ANASTASIS_KSD_INVALID_ANSWER,
+
+ /**
+ * To answer the challenge, the client should be redirected to
+ * the given URL.
+ */
+ ANASTASIS_KSD_REDIRECT_FOR_AUTHENTICATION,
+
+ /**
+ * The provider had an error.
+ */
+ ANASTASIS_KSD_SERVER_ERROR,
+
+ /**
+ * The provider claims we made an error.
+ */
+ ANASTASIS_KSD_CLIENT_FAILURE,
+
+ /**
+ * The provider does not know this truth.
+ */
+ ANASTASIS_KSD_TRUTH_UNKNOWN
+
+};
+
+
/**
* Detailed results from the successful download.
*/
struct ANASTASIS_KeyShareDownloadDetails
{
+
/**
- * The backup we downloaded
+ * Operational status.
*/
- const void *encrypted_key_share;
+ enum ANASTASIS_KeyShareDownloadStatus status;
/**
- * Number of bytes in @e encrypted_key_share.
+ * Anastasis URL that returned the @e status.
*/
- size_t encrypted_keyshare_size;
+ const char *server_url;
+
+ /**
+ * Details depending on @e status.
+ */
+ union
+ {
+
+ /**
+ * The encrypted key share (if @e status is #ANASTASIS_KSD_SUCCESS).
+ */
+ struct ANASTASIS_CRYPTO_EncryptedKeyShareP eks;
+
+ /**
+ * Response if the challenge sitll needs to be answered, and the
+ * instructions are provided inline (no redirection).
+ */
+ struct
+ {
+
+ /**
+ * HTTP status returned by the server. #MHD_HTTP_ALREADY_REPORTED
+ * if the server did already send the challenge to the user,
+ * #MHD_HTTP_FORBIDDEN if the answer was wrong (or missing).
+ */
+ unsigned int http_status;
+
+ /**
+ * Response with server-side instructions for the user
+ */
+ const char *instructions;
+
+ } open_challenge;
+
+ /**
+ * URL with instructions for the user to satisfy the challenge, if
+ * @e status is #ANASTASIS_KSD_REDIRECT_FOR_AUTHENTICATION.
+ */
+ const char *redirect_url;
+
+ /**
+ * Response with instructions for how to pay, if
+ * @e status is #ANASTASIS_KSD_PAYMENT_REQUIRED.
+ */
+ struct
+ {
+
+ /**
+ * "taler://pay" URL with details how to pay for the challenge.
+ */
+ const char *taler_pay_uri;
+
+ /**
+ * The order ID from @e taler_pay_uri.
+ */
+ struct ANASTASIS_PaymentSecretP payment_secret;
+
+ } payment_required;
+
+
+ /**
+ * Response with details about a server-side failure, if
+ * @e status is #ANASTASIS_KSD_SERVER_FAILURE,
+ * #ANASTASIS_KSD_CLIENT_FAILURE or #ANASTASIS_KSD_TRUTH_UNKNOWN.
+ */
+ struct
+ {
+
+ /**
+ * HTTP status returned by the server.
+ */
+ unsigned int http_status;
+
+ /**
+ * Taler-specific error code.
+ */
+ enum TALER_ErrorCode ec;
+
+ } server_failure;
+
+ } details;
};
@@ -409,13 +513,11 @@ struct ANASTASIS_KeyShareLookupOperation;
*
* @param cls closure
* @param http_status HTTP status code for this request
- * @param ec anastasis-specific error code
- * @param obj the response body
+ * @param kdd details about the key share
*/
typedef void
(*ANASTASIS_KeyShareLookupCallback) (
void *cls,
- unsigned int http_status,
const struct ANASTASIS_KeyShareDownloadDetails *kdd);
@@ -436,7 +538,7 @@ struct ANASTASIS_KeyShareLookupOperation *
ANASTASIS_keyshare_lookup (
struct GNUNET_CURL_Context *ctx,
const char *backend_url,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_public_key,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
const struct ANASTASIS_CRYPTO_TruthKeyP *truth_key,
const struct ANASTASIS_PaymentSecretP *payment_secret,
const struct GNUNET_HashCode *hashed_answer,
@@ -472,7 +574,7 @@ typedef void
/**
- * Store Truth, does a POST /truth/$TRUTH_PUBLIC_KEY
+ * Store Truth, does a POST /truth/$UUID
*
* @param ctx the CURL context used to connect to the backend
* @param backend_url backend's base URL, including final "/"
diff --git a/src/lib/anastasis_recovery.c b/src/lib/anastasis_recovery.c
index 4decaf3..7699a05 100644
--- a/src/lib/anastasis_recovery.c
+++ b/src/lib/anastasis_recovery.c
@@ -161,7 +161,7 @@ struct ANASTASIS_Challenge
/**
* The /truth GET operation handle.
*/
- struct ANASTASIS_ChallengeRunOperation *cro;
+ struct ANASTASIS_KeyShareLookupOperation *cro;
/**
* Callback which gives back the instructions and a status code of
@@ -203,6 +203,41 @@ keyshare_lookup_cb (void *cls,
http_status,
TALER_EC_NONE);
break;
+ case MHD_HTTP_PAYMENT_REQUIRED:
+ {
+ struct ANASTASIS_ChallengeStartResponse csr = {
+ .cs = ANASTASIS_CHALLENGE_STATUS_PAYMENT_REQUIRED,
+ .details.payment_required.server_url = c->ci.url,
+ .details.payment_required.taler_pay_url = response_string
+ };
+
+ c->csc (c->csc_cls,
+ &csr);
+ break;
+ }
+ case MHD_HTTP_OK:
+ {
+ struct ANASTASIS_ChallengeStartResponse csr = {
+ .cs = ANASTASIS_CHALLENGE_STATUS_INSTRUCTIONS,
+ .details.instructions = response_string
+ };
+
+ c->csc (c->csc_cls,
+ &csr);
+ break;
+ }
+ default:
+ {
+ struct ANASTASIS_ChallengeStartResponse csr = {
+ .cs = ANASTASIS_CHALLENGE_STATUS_SERVER_FAILURE,
+ .details.server_failure.message = response_string,
+ .details.server_failure.http_status = http_status
+ };
+
+ c->csc (c->csc_cls,
+ &csr);
+ break;
+ }
default:
c->af (c->af_cls,
http_status,
@@ -287,29 +322,20 @@ keyshare_lookup_cb (void *cls,
}
-void
-ANASTASIS_challenge_answer_cancel (struct ANASTASIS_Challenge *c)
+const struct ANASTASIS_ChallengeInformation *
+ANASTASIS_get_challenge (struct ANASTASIS_Challenge *challenge)
{
- if (NULL == c->kslo)
- {
- GNUNET_break (0);
- return;
- }
- ANASTASIS_keyshare_lookup_cancel (c->kslo);
- c->kslo = NULL;
+ return &challenge->ci;
}
int
-ANASTASIS_challenge_answer (
- struct ANASTASIS_Challenge *c,
- const struct ANASTASIS_PaymentSecretP *payment_secret,
- const char *answer_str,
- ANASTASIS_AnswerFeedback af,
- void *af_cls)
+ANASTASIS_challenge_start (struct ANASTASIS_Challenge *c,
+ const struct ANASTASIS_PaymentSecretP *psp,
+ const struct GNUNET_HashCode *hashed_answer,
+ ANASTASIS_AnswerFeedback af,
+ void *af_cls)
{
- struct GNUNET_HashCode hashed_answer;
-
if (c->ci.solved)
{
GNUNET_break (0);
@@ -317,15 +343,12 @@ ANASTASIS_challenge_answer (
}
c->af = af;
c->af_cls = af_cls;
- GNUNET_CRYPTO_hash (answer_str,
- strlen (answer_str),
- &hashed_answer);
c->kslo = ANASTASIS_keyshare_lookup (c->recovery->ctx,
c->ci.url,
&c->uuid,
&c->truth_key,
- payment_secret,
- &hashed_answer,
+ psp,
+ hashed_answer,
&keyshare_lookup_cb,
c);
if (NULL == c->kslo)
@@ -337,92 +360,45 @@ ANASTASIS_challenge_answer (
}
-const struct ANASTASIS_ChallengeInformation *
-ANASTASIS_get_challenge (struct ANASTASIS_Challenge *challenge)
-{
- return &challenge->ci;
-}
-
-
-/**
- * Function called with the results of a #ANASTASIS_challenge_run().
- *
- * @param cls closure
- * @param http_status HTTP status of the request
- * @param response_string payment request or instructions
- */
-static void
-challenge_run_cb (void *cls,
- unsigned int http_status,
- char *response_string)
+int
+ANASTASIS_challenge_answer (
+ struct ANASTASIS_Challenge *c,
+ const struct ANASTASIS_PaymentSecretP *psp,
+ const char *answer_str,
+ ANASTASIS_AnswerFeedback af,
+ void *af_cls)
{
- struct ANASTASIS_Challenge *c = cls;
-
- c->cro = NULL;
- switch (http_status)
- {
- case MHD_HTTP_PAYMENT_REQUIRED:
- {
- struct ANASTASIS_ChallengeStartResponse csr = {
- .cs = ANASTASIS_CHALLENGE_STATUS_PAYMENT_REQUIRED,
- .details.payment_required.server_url = c->ci.url,
- .details.payment_required.taler_pay_url = response_string
- };
-
- c->csc (c->csc_cls,
- &csr);
- break;
- }
- case MHD_HTTP_OK:
- {
- struct ANASTASIS_ChallengeStartResponse csr = {
- .cs = ANASTASIS_CHALLENGE_STATUS_INSTRUCTIONS,
- .details.instructions = response_string
- };
-
- c->csc (c->csc_cls,
- &csr);
- break;
- }
- default:
- {
- struct ANASTASIS_ChallengeStartResponse csr = {
- .cs = ANASTASIS_CHALLENGE_STATUS_SERVER_FAILURE,
- .details.server_failure.message = response_string,
- .details.server_failure.http_status = http_status
- };
+ struct GNUNET_HashCode hashed_answer;
- c->csc (c->csc_cls,
- &csr);
- break;
- }
- }
- c->csc = NULL;
- c->csc_cls = NULL;
+ GNUNET_CRYPTO_hash (answer_str,
+ strlen (answer_str),
+ &hashed_answer);
+ return ANASTASIS_challenge_start (c,
+ psp,
+ &hashed_answer,
+ af,
+ af_cls);
}
int
-ANASTASIS_challenge_start (struct ANASTASIS_Challenge *c,
- const struct ANASTASIS_PaymentSecretP *psp,
- ANASTASIS_ChallengeStartCallback csc,
- void *csc_cls)
+ANASTASIS_challenge_answer2 (struct ANASTASIS_Challenge *c,
+ const struct ANASTASIS_PaymentSecretP *psp,
+ uint64_t answer,
+ ANASTASIS_AnswerFeedback af,
+ void *af_cls)
{
- c->csc = csc;
- c->csc_cls = csc_cls;
- c->cro = ANASTASIS_challenge_run (c->recovery->ctx,
- c->ci.url,
- &c->uuid,
- &c->truth_key,
- psp,
- &challenge_run_cb,
- c);
- if (NULL == c->cro)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
+ char answer_s[40];
+
+ GNUNET_snprintf (answer_s,
+ sizeof (answer_s),
+ "%llu",
+ (unsigned long long) answer);
+ return ANASTASIS_challenge_answer2 (c,
+ psp,
+ answer_s,
+ af,
+ af_cls);
}
@@ -439,8 +415,8 @@ ANASTASIS_challenge_abort (struct ANASTASIS_Challenge *c)
GNUNET_break (0);
return;
}
- ANASTASIS_challenge_run_cancel (c->cro);
- c->cro = NULL;
+ ANASTASIS_keyshare_lookup_cancel (c->kslo);
+ c->kslo = NULL;
c->csc = NULL;
c->csc_cls = NULL;
}
@@ -775,6 +751,8 @@ ANASTASIS_recovery_begin (struct GNUNET_CURL_Context *ctx,
}
+]
+
void
ANASTASIS_recovery_abort (struct ANASTASIS_Recovery *r)
{
diff --git a/src/reducer/anastasis_api_backup_redux.c
b/src/reducer/anastasis_api_backup_redux.c
index a67c8f2..417b94a 100644
--- a/src/reducer/anastasis_api_backup_redux.c
+++ b/src/reducer/anastasis_api_backup_redux.c
@@ -1347,6 +1347,7 @@ initialize_policies (json_t *state,
json_t *json_truth
= json_array_get (json_object_get (state, "truths"),
atoi (tu_key));
+#if FIXME_LOGIC
if (json_integer_value (
json_object_get (json_truth, "auth_method_index"))
== auth_method_index)
@@ -1357,6 +1358,7 @@ initialize_policies (json_t *state,
truth_index++;
break;
}
+#endif
}
{
// initialize recovery document uploads array
@@ -1703,7 +1705,7 @@ truth_upload_cb (void *cls,
"status",
(json_int_t) MHD_HTTP_PAYMENT_REQUIRED,
"pay_url",
- ud->details.payment_request);
+ ud->details.payment.payment_request);
GNUNET_assert (NULL != p);
{
GNUNET_snprintf (buf,
@@ -1728,6 +1730,7 @@ truth_upload_cb (void *cls,
tus->truth = t;
truth_uploads = json_object_get (tus->state,
"truth_uploads");
+#if FIXME_LOGIC
j = ANASTASIS_truth_to_json (tus->truth);
GNUNET_assert (NULL != j);
p = json_pack ("{s:I,s:o}",
@@ -1735,6 +1738,7 @@ truth_upload_cb (void *cls,
(json_int_t) MHD_HTTP_NO_CONTENT,
"truth",
j);
+#endif
GNUNET_assert (NULL != p);
{
char buf[13];
diff --git a/src/reducer/anastasis_api_redux.c
b/src/reducer/anastasis_api_redux.c
index 6c9547b..2807979 100644
--- a/src/reducer/anastasis_api_redux.c
+++ b/src/reducer/anastasis_api_redux.c
@@ -928,9 +928,9 @@ policy_lookup_cb (void *cls,
bool contains = false;
for (unsigned int i = 0; i < rss->challenges_length; i++)
{
- if (0 == memcmp (&rss->challenges[i].nonce,
- &ci->nonce,
- sizeof(struct ANASTASIS_CRYPTO_NonceP)))
+ if (0 ==
+ GNUNET_memcmp (&rss->challenges[i].uuid,
+ &ci->uuid))
{
contains = true;
break;
@@ -942,7 +942,7 @@ policy_lookup_cb (void *cls,
rss->challenges_length,
*ci);
#if FIXME
- /* should probably only serialize the nonce and
+ /* should probably only serialize the uuid and
what the UI needs! */
GNUNET_assert (
0 == json_array_append_new (
@@ -955,19 +955,19 @@ policy_lookup_cb (void *cls,
{
json_t *policy = json_array ();
GNUNET_assert (json_is_array (policy));
- for (unsigned int j = 0; j < ri->dps[i].nonces_length; j++)
+ for (unsigned int j = 0; j < ri->dps[i].uuids_length; j++)
{
for (unsigned int k = 0; k < rss->challenges_length; k++)
{
- if (0 == memcmp (&ri->dps[i].nonces[j],
- &rss->challenges[k].nonce,
- sizeof (struct ANASTASIS_CRYPTO_NonceP)))
+ if (0 ==
+ GNUNET_memcmp (&ri->dps[i].uuids[j],
+ &rss->challenges[k].uuid))
GNUNET_assert (
0 == json_array_append_new (policy,
json_integer ((json_int_t) k)));
}
}
- GNUNET_free (ri->dps[i].nonces);
+ GNUNET_free (ri->dps[i].uuids);
if (0 < json_array_size (policy))
GNUNET_assert (
0 == json_array_append_new (policies,
diff --git a/src/restclient/anastasis_api_keyshare_lookup.c
b/src/restclient/anastasis_api_keyshare_lookup.c
index fd64f97..f65f6a1 100644
--- a/src/restclient/anastasis_api_keyshare_lookup.c
+++ b/src/restclient/anastasis_api_keyshare_lookup.c
@@ -26,6 +26,8 @@
#include <microhttpd.h> /* just for HTTP status codes */
#include "anastasis_service.h"
#include "anastasis_api_curl_defaults.h"
+#include <taler/taler_json_lib.h>
+#include <taler/taler_merchant_service.h>
/**
@@ -38,6 +40,11 @@ struct ANASTASIS_KeyShareLookupOperation
*/
char *url;
+ /**
+ * The url for this request, without response parameter.
+ */
+ char *display_url;
+
/**
* Handle for the request.
*/
@@ -73,6 +80,15 @@ struct ANASTASIS_KeyShareLookupOperation
*/
const struct GNUNET_HashCode *hashed_answer;
+ /**
+ * Payment URI we received from the service, or NULL.
+ */
+ char *pay_uri;
+
+ /**
+ * Location URI we received from the service, or NULL.
+ */
+ char *location;
};
@@ -85,6 +101,9 @@ ANASTASIS_keyshare_lookup_cancel (
GNUNET_CURL_job_cancel (kslo->job);
kslo->job = NULL;
}
+ GNUNET_free (kslo->location);
+ GNUNET_free (kslo->pay_uri);
+ GNUNET_free (kslo->display_url);
GNUNET_free (kslo->url);
GNUNET_free (kslo);
}
@@ -92,6 +111,11 @@ ANASTASIS_keyshare_lookup_cancel (
/**
* Process GET /truth response
+ *
+ * @param cls our `struct ANASTASIS_KeyShareLookupOperation *`
+ * @param response_code the HTTP status
+ * @param data the body of the response
+ * @param data_size number of bytes in @a data
*/
static void
handle_keyshare_lookup_finished (void *cls,
@@ -100,68 +124,215 @@ handle_keyshare_lookup_finished (void *cls,
size_t data_size)
{
struct ANASTASIS_KeyShareLookupOperation *kslo = cls;
+ struct ANASTASIS_KeyShareDownloadDetails kdd;
kslo->job = NULL;
+ memset (&kdd,
+ 0,
+ sizeof (kdd));
+ kdd.server_url = kslo->display_url;
switch (response_code)
{
case 0:
/* Hard error */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Backend didn't even return from GET /truth\n");
+ kdd.status = ANASTASIS_KSD_SERVER_ERROR;
break;
-
case MHD_HTTP_OK:
+ if (sizeof (struct ANASTASIS_CRYPTO_EncryptedKeyShareP) == data_size)
{
- struct ANASTASIS_KeyShareDownloadDetails kdd;
-
/* Success, call callback with all details! */
- memset (&kdd, 0, sizeof (kdd));
- kdd.encrypted_key_share = data;
- kdd.encrypted_keyshare_size = data_size;
+ memcpy (&kdd.details.eks,
+ data,
+ data_size);
kslo->cb (kslo->cb_cls,
- (unsigned int) response_code,
&kdd);
- kslo->cb = NULL;
ANASTASIS_keyshare_lookup_cancel (kslo);
return;
}
- case MHD_HTTP_ALREADY_REPORTED:
- /* Nothing really to verify */
- break;
+ else
+ {
+ GNUNET_break_op (0);
+ kdd.status = ANASTASIS_KSD_SERVER_ERROR;
+ break;
+ }
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the anastasis server is buggy
(or API version conflict); just pass JSON reply to the application */
+ GNUNET_break (0);
+ kdd.status = ANASTASIS_KSD_CLIENT_FAILURE;
break;
- case MHD_HTTP_FORBIDDEN:
- /* Nothing really to verify, authentication failed */
+ case MHD_HTTP_PAYMENT_REQUIRED:
+ {
+ struct TALER_MERCHANT_PayUriData pd;
+
+ if ( (NULL == kslo->pay_uri) ||
+ (GNUNET_OK !=
+ TALER_MERCHANT_parse_pay_uri (kslo->pay_uri,
+ &pd)) )
+ {
+ GNUNET_break_op (0);
+ kdd.status = ANASTASIS_KSD_SERVER_ERROR;
+ break;
+ }
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (
+ pd.order_id,
+ strlen (pd.order_id),
+ &kdd.details.payment_required.payment_secret,
+ sizeof (kdd.details.payment_required.payment_secret)))
+ {
+ GNUNET_break (0);
+ kdd.status = ANASTASIS_KSD_SERVER_ERROR;
+ break;
+ }
+ kdd.status = ANASTASIS_KSD_PAYMENT_REQUIRED;
+ kdd.details.payment_required.taler_pay_uri = kslo->pay_uri;
+ kslo->cb (kslo->cb_cls,
+ &kdd);
+ ANASTASIS_keyshare_lookup_cancel (kslo);
+ return;
+ }
break;
+ case MHD_HTTP_SEE_OTHER:
+ /* Nothing really to verify, authentication required/failed */
+ kdd.status = ANASTASIS_KSD_REDIRECT_FOR_AUTHENTICATION;
+ kdd.details.redirect_url = kslo->location;
+ kslo->cb (kslo->cb_cls,
+ &kdd);
+ ANASTASIS_keyshare_lookup_cancel (kslo);
+ return;
+ case MHD_HTTP_ALREADY_REPORTED:
+ case MHD_HTTP_FORBIDDEN:
+ /* Nothing really to verify, authentication required/failed */
+ {
+ char *instructions;
+
+ instructions = GNUNET_strndup (data,
+ data_size);
+ kdd.status = ANASTASIS_KSD_INVALID_ANSWER;
+ kdd.details.open_challenge.instructions = instructions;
+ kdd.details.open_challenge.http_status = response_code;
+ kslo->cb (kslo->cb_cls,
+ &kdd);
+ GNUNET_free (instructions);
+ }
+ ANASTASIS_keyshare_lookup_cancel (kslo);
+ return;
case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify */
+ kdd.status = ANASTASIS_KSD_TRUTH_UNKNOWN;
break;
case MHD_HTTP_GONE:
/* Nothing really to verify */
+ kdd.status = ANASTASIS_KSD_TRUTH_UNKNOWN;
+ break;
+ case MHD_HTTP_EXPECTATION_FAILED:
+ /* Nothing really to verify */
+ kdd.status = ANASTASIS_KSD_CLIENT_FAILURE;
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
+ kdd.status = ANASTASIS_KSD_SERVER_ERROR;
break;
default:
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u\n",
+ "Unexpected response code %u to GET /truth\n",
(unsigned int) response_code);
GNUNET_break (0);
- response_code = 0;
+ kdd.status = ANASTASIS_KSD_SERVER_ERROR;
break;
}
- if (NULL != kslo->cb)
+ kdd.details.server_failure.ec = TALER_JSON_get_error_code2 (data,
+ data_size);
+ kdd.details.server_failure.http_status = response_code;
+ kslo->cb (kslo->cb_cls,
+ &kdd);
+ ANASTASIS_keyshare_lookup_cancel (kslo);
+}
+
+
+/**
+ * Handle HTTP header received by curl.
+ *
+ * @param buffer one line of HTTP header data
+ * @param size size of an item
+ * @param nitems number of items passed
+ * @param userdata our `struct ANASTASIS_StorePolicyOperation *`
+ * @return `size * nitems`
+ */
+static size_t
+handle_header (char *buffer,
+ size_t size,
+ size_t nitems,
+ void *userdata)
+{
+ struct ANASTASIS_KeyShareLookupOperation *kslo = userdata;
+ size_t total = size * nitems;
+ char *ndup;
+ const char *hdr_type;
+ char *hdr_val;
+ char *sp;
+
+ ndup = GNUNET_strndup (buffer,
+ total);
+ hdr_type = strtok_r (ndup,
+ ":",
+ &sp);
+ if (NULL == hdr_type)
{
- kslo->cb (kslo->cb_cls,
- response_code,
- NULL);
- kslo->cb = NULL;
+ GNUNET_free (ndup);
+ return total;
}
- ANASTASIS_keyshare_lookup_cancel (kslo);
+ hdr_val = strtok_r (NULL,
+ "",
+ &sp);
+ if (NULL == hdr_val)
+ {
+ GNUNET_free (ndup);
+ return total;
+ }
+ if (' ' == *hdr_val)
+ hdr_val++;
+ if (0 == strcasecmp (hdr_type,
+ ANASTASIS_HTTP_HEADER_TALER))
+ {
+ size_t len;
+
+ /* found payment URI we care about! */
+ GNUNET_free (kslo->pay_uri);
+ kslo->pay_uri = GNUNET_strdup (hdr_val);
+ len = strlen (kslo->pay_uri);
+ while ( (len > 0) &&
+ ( ('\n' == kslo->pay_uri[len - 1]) ||
+ ('\r' == kslo->pay_uri[len - 1]) ) )
+ {
+ len--;
+ kslo->pay_uri[len] = '\0';
+ }
+ }
+ if (0 == strcasecmp (hdr_type,
+ MHD_HTTP_HEADER_LOCATION))
+ {
+ size_t len;
+
+ /* found location URI we care about! */
+ GNUNET_free (kslo->location);
+ kslo->location = GNUNET_strdup (hdr_val);
+ len = strlen (kslo->location);
+ while ( (len > 0) &&
+ ( ('\n' == kslo->location[len - 1]) ||
+ ('\r' == kslo->location[len - 1]) ) )
+ {
+ len--;
+ kslo->location[len] = '\0';
+ }
+ }
+ GNUNET_free (ndup);
+ return total;
}
@@ -169,7 +340,7 @@ struct ANASTASIS_KeyShareLookupOperation *
ANASTASIS_keyshare_lookup (
struct GNUNET_CURL_Context *ctx,
const char *backend_url,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_public_key,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
const struct ANASTASIS_CRYPTO_TruthKeyP *truth_key,
const struct ANASTASIS_PaymentSecretP *payment_secret,
const struct GNUNET_HashCode *hashed_answer,
@@ -236,26 +407,45 @@ ANASTASIS_keyshare_lookup (
kslo->ctx = ctx;
kslo->truth_key = truth_key;
{
- char *pub_key_str;
+ char *uuid_str;
- pub_key_str = GNUNET_STRINGS_data_to_string_alloc (truth_public_key,
- sizeof
(*truth_public_key));
+ uuid_str = GNUNET_STRINGS_data_to_string_alloc (truth_uuid,
+ sizeof (*truth_uuid));
GNUNET_asprintf (&path,
"truth/%s",
- pub_key_str);
- GNUNET_free (pub_key_str);
+ uuid_str);
+ GNUNET_free (uuid_str);
+ }
+ if (NULL != hashed_answer)
+ {
+ answer_s = GNUNET_STRINGS_data_to_string_alloc (hashed_answer,
+ sizeof (*hashed_answer));
+ kslo->url = TALER_url_join (backend_url,
+ path,
+ "response",
+ answer_s,
+ NULL);
+ GNUNET_free (answer_s);
+ }
+ else
+ {
+ kslo->url = TALER_url_join (backend_url,
+ path,
+ NULL);
}
- answer_s = GNUNET_STRINGS_data_to_string_alloc (hashed_answer,
- sizeof (*hashed_answer));
-
- kslo->url = TALER_url_join (backend_url,
- path,
- "response",
- answer_s,
- NULL);
- GNUNET_free (answer_s);
+ kslo->display_url = TALER_url_join (backend_url,
+ path,
+ NULL);
GNUNET_free (path);
eh = ANASTASIS_curl_easy_get_ (kslo->url);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_HEADERFUNCTION,
+ &handle_header));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_HEADERDATA,
+ kslo));
kslo->cb = cb;
kslo->cb_cls = cb_cls;
kslo->job = GNUNET_CURL_job_add_raw (ctx,
@@ -263,7 +453,6 @@ ANASTASIS_keyshare_lookup (
job_headers,
&handle_keyshare_lookup_finished,
kslo);
- GNUNET_free (path);
curl_slist_free_all (job_headers);
return kslo;
}
diff --git a/src/restclient/anastasis_api_truth_store.c
b/src/restclient/anastasis_api_truth_store.c
index 7183930..5d5723c 100644
--- a/src/restclient/anastasis_api_truth_store.c
+++ b/src/restclient/anastasis_api_truth_store.c
@@ -157,23 +157,10 @@ handle_truth_store_finished (void *cls,
ud.details.payment.payment_request = tso->pay_uri;
udp = &ud;
break;
- case MHD_HTTP_FORBIDDEN:
- GNUNET_break (0);
- ud.ec = TALER_JSON_get_error_code2 (data,
- data_size);
- break;
case MHD_HTTP_CONFLICT:
ud.us = ANASTASIS_US_CONFLICTING_TRUTH;
- ud.details.recovered_backup.existing_backup_size
- = data_size;
- ud.details.recovered_backup.existing_backup
- = data;
udp = &ud;
break;
- case MHD_HTTP_GONE:
- ud.ec = TALER_JSON_get_error_code2 (data,
- data_size);
- break;
case MHD_HTTP_LENGTH_REQUIRED:
GNUNET_break (0);
break;
diff --git a/src/stasis/plugin_anastasis_postgres.c
b/src/stasis/plugin_anastasis_postgres.c
index d81b27b..ded0423 100644
--- a/src/stasis/plugin_anastasis_postgres.c
+++ b/src/stasis/plugin_anastasis_postgres.c
@@ -845,6 +845,71 @@ postgres_record_recdoc_payment (
}
+/**
+ * Record truth upload payment was made.
+ *
+ * @param cls closure
+ * @param uuid the truth's UUID
+ * @param amount the amount that was paid
+ * @param duration how long is the truth paid for
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_record_truth_upload_payment (
+ void *cls,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid,
+ const struct TALER_Amount *amount,
+ struct GNUNET_TIME_Relative duration)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_TIME_Absolute exp = GNUNET_TIME_relative_to_absolute
(duration);
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (uuid),
+ TALER_PQ_query_param_amount (amount),
+ GNUNET_PQ_query_param_absolute_time (&exp),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "truth_payment_insert",
+ params);
+}
+
+
+/**
+ * Inquire whether truth upload payment was made.
+ *
+ * @param cls closure
+ * @param uuid the truth's UUID
+ * @param[out] paid_until set for how long this truth is paid for
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_check_truth_upload_paid (
+ void *cls,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid,
+ struct GNUNET_TIME_Absolute *paid_until)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (uuid),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_absolute_time ("expiration",
+ paid_until),
+ GNUNET_PQ_result_spec_end
+ };
+
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "truth_payment_select",
+ params,
+ rs);
+}
+
+
/**
* Store payment for challenge.
*
@@ -1722,6 +1787,15 @@ libanastasis_plugin_db_postgres_init (void *cls)
") VALUES "
"($1, $2, $3, $4, $5);",
5),
+ GNUNET_PQ_make_prepare ("truth_payment_insert",
+ "INSERT INTO anastasis_truth_payment "
+ "(truth_uuid"
+ ",amount_val"
+ ",amount_frac"
+ ",expiration"
+ ") VALUES "
+ "($1, $2, $3, $4);",
+ 4),
GNUNET_PQ_make_prepare ("recdoc_payment_done",
"UPDATE anastasis_recdoc_payment "
"SET"
@@ -1754,6 +1828,12 @@ libanastasis_plugin_db_postgres_init (void *cls)
" FROM anastasis_recdoc_payment"
" WHERE payment_identifier=$1;",
1),
+ GNUNET_PQ_make_prepare ("truth_payment_select",
+ "SELECT"
+ " expiration"
+ " FROM anastasis_truth_payment"
+ " WHERE truth_uuid=$1;",
+ 1),
GNUNET_PQ_make_prepare ("challenge_payment_select",
"SELECT"
" creation_date"
@@ -2006,6 +2086,8 @@ libanastasis_plugin_db_postgres_init (void *cls)
plugin->create_challenge_code = &postgres_create_challenge_code;
plugin->mark_challenge_sent = &postgres_mark_challenge_sent;
plugin->challenge_gc = &postgres_challenge_gc;
+ plugin->record_truth_upload_payment = &postgres_record_truth_upload_payment;
+ plugin->check_truth_upload_paid = &postgres_check_truth_upload_paid;
plugin->record_challenge_payment = &postgres_record_challenge_payment;
plugin->check_challenge_payment = &postgres_check_challenge_payment;
plugin->lookup_challenge_payment = &postgres_lookup_challenge_payment;
diff --git a/src/stasis/stasis-0001.sql b/src/stasis/stasis-0001.sql
index 5dd278e..8bca886 100644
--- a/src/stasis/stasis-0001.sql
+++ b/src/stasis/stasis-0001.sql
@@ -17,15 +17,27 @@
-- Everything in one big transaction
BEGIN;
--- TODO:
--- * add comments for every table and column
--- * avoid 'method' as column name (SQL keyword!)
-
-
-- Check patch versioning is in place.
SELECT _v.register_patch('stasis-0001', NULL, NULL);
+CREATE TABLE IF NOT EXISTS anastasis_truth_payment
+ (truth_uuid BYTEA PRIMARY KEY CHECK(LENGTH(truth_uuid)=32),
+ amount_val INT8 NOT NULL,
+ amount_frac INT4 NOT NULL,
+ expiration INT8 NOT NULL);
+COMMENT ON TABLE anastasis_truth_payment
+ IS 'Records about payments for truth uploads';
+COMMENT ON COLUMN anastasis_truth_payment.truth_uuid
+ IS 'Identifier of the truth';
+COMMENT ON COLUMN anastasis_truth_payment.amount_val
+ IS 'Amount we were paid';
+COMMENT ON COLUMN anastasis_truth_payment.amount_frac
+ IS 'Amount we were paid fraction';
+COMMENT ON COLUMN anastasis_truth_payment.expiration
+ IS 'At which date will the truth payment expire';
+
+
CREATE TABLE IF NOT EXISTS anastasis_truth
(truth_uuid BYTEA PRIMARY KEY CHECK(LENGTH(truth_uuid)=32),
key_share_data BYTEA CHECK(LENGTH(key_share_data)=80) NOT NULL,
@@ -36,7 +48,7 @@ CREATE TABLE IF NOT EXISTS anastasis_truth
COMMENT ON TABLE anastasis_truth
IS 'Truth data is needed to authenticate clients during recovery';
COMMENT ON COLUMN anastasis_truth.truth_uuid
- IS 'The truth UUID uniquely identifies this truth record';
+ IS 'The truth UUID uniquely identifies this truth record. Not a foreign key
as we may offer storing truth for free.';
COMMENT ON COLUMN anastasis_truth.key_share_data
IS 'Stores the encrypted key share used to recover the key (nonce, tag and
keyshare)';
COMMENT ON COLUMN anastasis_truth.method_name
@@ -48,6 +60,7 @@ COMMENT ON COLUMN anastasis_truth.truth_mime
COMMENT ON COLUMN anastasis_truth.expiration
IS 'At which date will the truth record expire';
+
CREATE TABLE IF NOT EXISTS anastasis_user
(user_id BYTEA PRIMARY KEY CHECK(LENGTH(user_id)=32),
expiration_date INT8 NOT NULL);
@@ -58,6 +71,7 @@ COMMENT ON COLUMN anastasis_user.user_id
COMMENT ON COLUMN anastasis_user.expiration_date
IS 'At which date will the user record expire';
+
CREATE TABLE IF NOT EXISTS anastasis_recdoc_payment
(payment_id BIGSERIAL PRIMARY KEY,
user_id BYTEA NOT NULL REFERENCES anastasis_user(user_id),
@@ -86,6 +100,7 @@ COMMENT ON COLUMN anastasis_recdoc_payment.creation_date
COMMENT ON COLUMN anastasis_recdoc_payment.paid
IS 'Is the payment finished';
+
CREATE TABLE IF NOT EXISTS anastasis_challenge_payment
(payment_id BIGSERIAL PRIMARY KEY,
truth_uuid BYTEA CHECK(LENGTH(truth_uuid)=32) NOT NULL,
@@ -112,6 +127,7 @@ COMMENT ON COLUMN anastasis_challenge_payment.creation_date
COMMENT ON COLUMN anastasis_challenge_payment.paid
IS 'Is the payment finished';
+
CREATE TABLE IF NOT EXISTS anastasis_recoverydocument
(user_id BYTEA NOT NULL REFERENCES anastasis_user(user_id),
version INT4 NOT NULL,
@@ -132,6 +148,7 @@ COMMENT ON COLUMN
anastasis_recoverydocument.recovery_data_hash
COMMENT ON COLUMN anastasis_recoverydocument.recovery_data
IS 'Contains the encrypted policy and core secret';
+
CREATE TABLE IF NOT EXISTS anastasis_challengecode
(truth_uuid BYTEA PRIMARY KEY CHECK(LENGTH(truth_uuid)=32) NOT NULL,
code INT8 NOT NULL,
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-anastasis] branch master updated: enable payment for truth upload, misc fixes,
gnunet <=