[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-anastasis] branch master updated: implement #6750
From: |
gnunet |
Subject: |
[taler-anastasis] branch master updated: implement #6750 |
Date: |
Sat, 10 Apr 2021 16:27:43 +0200 |
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 cdc01c1 implement #6750
cdc01c1 is described below
commit cdc01c1f6d38a6b45786a9c0b2ec1df097b88219
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sat Apr 10 16:27:40 2021 +0200
implement #6750
---
src/backend/anastasis-httpd_truth.c | 169 +++++++++++++++++++++++++++++++-
src/include/anastasis_database_plugin.h | 15 +++
src/stasis/plugin_anastasis_postgres.c | 49 ++++++++-
src/stasis/stasis-0001.sql | 5 +-
4 files changed, 233 insertions(+), 5 deletions(-)
diff --git a/src/backend/anastasis-httpd_truth.c
b/src/backend/anastasis-httpd_truth.c
index 42aa452..6a94ce8 100644
--- a/src/backend/anastasis-httpd_truth.c
+++ b/src/backend/anastasis-httpd_truth.c
@@ -44,6 +44,13 @@
#define CHECK_PAYMENT_GENERIC_TIMEOUT GNUNET_TIME_relative_multiply ( \
GNUNET_TIME_UNIT_MINUTES, 30)
+/**
+ * How long should the wallet check for auto-refunds before giving up?
+ */
+#define AUTO_REFUND_TIMEOUT GNUNET_TIME_relative_multiply ( \
+ GNUNET_TIME_UNIT_MINUTES, 2)
+
+
/**
* How many retries do we allow per code?
*/
@@ -152,10 +159,55 @@ struct GetContext
*/
bool have_response;
+};
+
+/**
+ * Information we track for refunds.
+ */
+struct RefundEntry
+{
+ /**
+ * Kept in a DLL.
+ */
+ struct RefundEntry *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct RefundEntry *prev;
+
+ /**
+ * Operation handle.
+ */
+ struct TALER_MERCHANT_OrderRefundHandle *ro;
+
+ /**
+ * Which order is being refunded.
+ */
+ char *order_id;
+
+ /**
+ * Payment Identifier
+ */
+ struct ANASTASIS_PaymentSecretP payment_identifier;
+ /**
+ * Public key of the challenge which is solved.
+ */
+ struct ANASTASIS_CRYPTO_TruthUUIDP truth_uuid;
};
+/**
+ * Head of linked list of active refund operations.
+ */
+static struct RefundEntry *re_head;
+
+/**
+ * Tail of linked list of active refund operations.
+ */
+static struct RefundEntry *re_tail;
+
/**
* Head of linked list over all authorization processes
*/
@@ -171,6 +223,20 @@ void
AH_truth_shutdown (void)
{
struct GetContext *gc;
+ struct RefundEntry *re;
+
+ while (NULL != (re = re_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (re_head,
+ re_tail,
+ re);
+ TALER_MERCHANT_post_order_refund_cancel (re->ro);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Refund `%s' failed due to shutdown\n",
+ re->order_id);
+ GNUNET_free (re->order_id);
+ GNUNET_free (re);
+ }
while (NULL != (gc = gc_head))
{
@@ -204,6 +270,99 @@ AH_truth_shutdown (void)
}
+/**
+ * Callback to process a POST /orders/ID/refund request
+ *
+ * @param cls closure
+ * @param http_status HTTP status code for this request
+ * @param ec taler-specific error code
+ * @param taler_refund_uri the refund uri offered to the wallet
+ * @param h_contract hash of the contract a Browser may need to authorize
+ * obtaining the HTTP response.
+ */
+static void
+refund_cb (
+ void *cls,
+ const struct TALER_MERCHANT_HttpResponse *hr,
+ const char *taler_refund_uri,
+ const struct GNUNET_HashCode *h_contract)
+{
+ struct RefundEntry *re = cls;
+
+ re->ro = NULL;
+ switch (hr->http_status)
+ {
+ case MHD_HTTP_OK:
+ {
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = db->record_challenge_refund (db->cls,
+ &re->truth_uuid,
+ &re->payment_identifier);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ break;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break (0);
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+ }
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Refund `%s' failed with HTTP status %u: %s (#%u)\n",
+ re->order_id,
+ hr->http_status,
+ hr->hint,
+ (unsigned int) hr->ec);
+ }
+ GNUNET_CONTAINER_DLL_remove (re_head,
+ re_tail,
+ re);
+ GNUNET_free (re->order_id);
+ GNUNET_free (re);
+}
+
+
+/**
+ * Start to give a refund for the challenge created by @a gc.
+ *
+ * @param gc request where we failed and should now grant a refund for
+ */
+static void
+begin_refund (const struct GetContext *gc)
+{
+ struct RefundEntry *re;
+
+ re = GNUNET_new (struct RefundEntry);
+ re->order_id = GNUNET_STRINGS_data_to_string_alloc (
+ &gc->payment_identifier,
+ sizeof (gc->payment_identifier));
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Challenge execution failed, triggering refund for order `%s'\n",
+ re->order_id);
+ re->payment_identifier = gc->payment_identifier;
+ re->truth_uuid = gc->truth_uuid;
+ re->ro = TALER_MERCHANT_post_order_refund (AH_ctx,
+ AH_backend_url,
+ re->order_id,
+ &gc->challenge_cost,
+ "failed to issue challenge",
+ &refund_cb,
+ re);
+ GNUNET_CONTAINER_DLL_insert (re_head,
+ re_tail,
+ re);
+}
+
+
/**
* Callback used to notify the application about completed requests.
* Cleans up the requests data structures.
@@ -553,10 +712,12 @@ begin_payment (struct GetContext *gc)
pay_deadline = GNUNET_TIME_relative_to_absolute (
ANASTASIS_CHALLENGE_OFFER_LIFETIME);
GNUNET_TIME_round_abs (&pay_deadline);
- order = json_pack ("{s:o, s:s, s:s, s:o}",
+ order = json_pack ("{s:o, s:s, s:s, s:o, s:o}",
"amount", TALER_JSON_from_amount (&gc->challenge_cost),
"summary", "challenge fee for anastasis service",
"order_id", order_id,
+ "auto_refund", GNUNET_JSON_from_time_rel (
+ AUTO_REFUND_TIMEOUT),
"pay_deadline", GNUNET_JSON_from_time_abs (
pay_deadline));
gc->po = TALER_MERCHANT_orders_post2 (AH_ctx,
@@ -668,8 +829,10 @@ run_authorization_process (struct MHD_Connection
*connection,
gc->as = NULL;
return MHD_YES;
case ANASTASIS_AUTHORIZATION_RES_FAILED:
- /* Challenge transmission failed, our fault! */
- // FIXME #6750: give at least a refund!?
+ if (gc->payment_identifier_provided)
+ {
+ begin_refund (gc);
+ }
gc->authorization->cleanup (gc->as);
gc->as = NULL;
return MHD_YES;
diff --git a/src/include/anastasis_database_plugin.h
b/src/include/anastasis_database_plugin.h
index d51ac6b..4853375 100644
--- a/src/include/anastasis_database_plugin.h
+++ b/src/include/anastasis_database_plugin.h
@@ -591,6 +591,21 @@ struct ANASTASIS_DatabasePlugin
const struct TALER_Amount *amount);
+ /**
+ * Record refund for challenge.
+ *
+ * @param cls closure
+ * @param truth_key identifier of the challenge to pay
+ * @param payment_secret payment secret which the user must provide with
every upload
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*record_challenge_refund)(
+ void *cls,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const struct ANASTASIS_PaymentSecretP *payment_secret);
+
+
/**
* Lookup for a pending payment for a certain challenge
*
diff --git a/src/stasis/plugin_anastasis_postgres.c
b/src/stasis/plugin_anastasis_postgres.c
index 977d2f1..6750e47 100644
--- a/src/stasis/plugin_anastasis_postgres.c
+++ b/src/stasis/plugin_anastasis_postgres.c
@@ -945,6 +945,34 @@ postgres_record_challenge_payment (
}
+/**
+ * Store refund granted for challenge.
+ *
+ * @param cls closure
+ * @param truth_key identifier of the challenge to pay
+ * @param payment_secret payment secret which the user must provide with every
upload
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_record_challenge_refund (
+ void *cls,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ const struct ANASTASIS_PaymentSecretP *payment_secret)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (payment_secret),
+ GNUNET_PQ_query_param_auto_from_type (truth_uuid),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "challenge_refund_update",
+ params);
+}
+
+
/**
* Check payment identifier. Used to check if a payment identifier given by
* the user is valid (existing and paid).
@@ -1842,6 +1870,17 @@ libanastasis_plugin_db_postgres_init (void *cls)
" AND"
" paid=FALSE;",
2),
+ GNUNET_PQ_make_prepare ("challenge_refund_update",
+ "UPDATE anastasis_challenge_payment "
+ "SET"
+ " refunded=TRUE "
+ "WHERE"
+ " payment_identifier=$1"
+ " AND"
+ " paid=TRUE"
+ " AND"
+ " truth_uuid=$2;",
+ 2),
GNUNET_PQ_make_prepare ("challenge_payment_done",
"UPDATE anastasis_challenge_payment "
"SET"
@@ -1849,6 +1888,8 @@ libanastasis_plugin_db_postgres_init (void *cls)
"WHERE"
" payment_identifier=$1"
" AND"
+ " refunded=FALSE"
+ " AND"
" truth_uuid=$2"
" AND"
" paid=FALSE;",
@@ -1879,6 +1920,7 @@ libanastasis_plugin_db_postgres_init (void *cls)
" FROM anastasis_challenge_payment"
" WHERE payment_identifier=$1"
" AND truth_uuid=$2"
+ " AND refunded=FALSE"
" AND counter>0;",
1),
GNUNET_PQ_make_prepare ("challenge_pending_payment_select",
@@ -1891,6 +1933,8 @@ libanastasis_plugin_db_postgres_init (void *cls)
" WHERE"
" paid=FALSE"
" AND"
+ " refunded=FALSE"
+ " AND"
" truth_uuid=$1"
" AND"
" creation_date > $2;",
@@ -1931,7 +1975,9 @@ libanastasis_plugin_db_postgres_init (void *cls)
GNUNET_PQ_make_prepare ("gc_challenge_pending_payments",
"DELETE FROM anastasis_challenge_payment "
"WHERE"
- " paid=FALSE"
+ " (paid=FALSE"
+ " OR"
+ " refunded=TRUE)"
" AND"
" creation_date < $1;",
1),
@@ -2133,6 +2179,7 @@ libanastasis_plugin_db_postgres_init (void *cls)
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->record_challenge_refund = &postgres_record_challenge_refund;
plugin->check_challenge_payment = &postgres_check_challenge_payment;
plugin->lookup_challenge_payment = &postgres_lookup_challenge_payment;
plugin->update_challenge_payment = &postgres_update_challenge_payment;
diff --git a/src/stasis/stasis-0001.sql b/src/stasis/stasis-0001.sql
index 7025029..beb886d 100644
--- a/src/stasis/stasis-0001.sql
+++ b/src/stasis/stasis-0001.sql
@@ -109,7 +109,8 @@ CREATE TABLE IF NOT EXISTS anastasis_challenge_payment
payment_identifier BYTEA NOT NULL CHECK(LENGTH(payment_identifier)=32),
creation_date INT8 NOT NULL,
counter INT4 NOT NULL DEFAULT 3,
- paid BOOLEAN NOT NULL DEFAULT FALSE
+ paid BOOLEAN NOT NULL DEFAULT FALSE,
+ refunded BOOLEAN NOT NULL DEFAULT FALSE
);
COMMENT ON TABLE anastasis_recdoc_payment
IS 'Records a payment for a challenge';
@@ -129,6 +130,8 @@ COMMENT ON COLUMN anastasis_challenge_payment.creation_date
IS 'Creation date of the payment';
COMMENT ON COLUMN anastasis_challenge_payment.paid
IS 'Is the payment finished';
+COMMENT ON COLUMN anastasis_challenge_payment.refunded
+ IS 'Was the payment refunded';
CREATE TABLE IF NOT EXISTS anastasis_recoverydocument
--
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: implement #6750,
gnunet <=