[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-anastasis] branch master updated: errors
From: |
gnunet |
Subject: |
[taler-anastasis] branch master updated: errors |
Date: |
Wed, 11 Nov 2020 21:27:04 +0100 |
This is an automated email from the git hooks/post-receive script.
ds-meister pushed a commit to branch master
in repository anastasis.
The following commit(s) were added to refs/heads/master by this push:
new ffb54c5 errors
ffb54c5 is described below
commit ffb54c52cdf6a509c5ea5eeb3495b9e50507c0c1
Author: Dominik Meister <dominik.meister@hotmail.ch>
AuthorDate: Wed Nov 11 21:26:18 2020 +0100
errors
---
src/backend/anastasis-httpd.c | 16 ++
src/backend/anastasis-httpd.h | 5 +
src/backend/anastasis-httpd_truth.c | 398 +++++++++++++++---------------
src/include/anastasis_service.h | 4 +-
src/lib/anastasis.c | 21 ++
src/lib/anastasis_api_keyshare_lookup.c | 41 +--
src/lib/testing_api_cmd_challenge_run.c | 12 +-
src/lib/testing_api_cmd_keyshare_lookup.c | 2 +-
8 files changed, 275 insertions(+), 224 deletions(-)
diff --git a/src/backend/anastasis-httpd.c b/src/backend/anastasis-httpd.c
index bc97bc8..37ee6f8 100644
--- a/src/backend/anastasis-httpd.c
+++ b/src/backend/anastasis-httpd.c
@@ -86,6 +86,10 @@ struct TALER_Amount AH_video_cost;
* Cost of authentication by sms
*/
struct TALER_Amount AH_sms_cost;
+/**
+ * Cost of authentication by file (used for testing only)
+ */
+struct TALER_Amount AH_file_cost;
/**
* Our Taler backend to process payments.
@@ -615,6 +619,18 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
+ if (GNUNET_OK !=
+ TALER_config_get_amount (config,
+ "anastasis",
+ "FILE_COST",
+ &AH_file_cost))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "anastasis",
+ "FILE_COST");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
if (GNUNET_OK !=
TALER_config_get_currency (config,
&AH_currency))
diff --git a/src/backend/anastasis-httpd.h b/src/backend/anastasis-httpd.h
index b475bf4..a8f2655 100644
--- a/src/backend/anastasis-httpd.h
+++ b/src/backend/anastasis-httpd.h
@@ -164,6 +164,11 @@ extern struct TALER_Amount AH_email_cost;
*/
extern struct TALER_Amount AH_post_cost;
+/**
+ * Cost of authentication by file (for testing only)
+ */
+extern struct TALER_Amount AH_file_cost;
+
/**
* Cost of authentication by video
*/
diff --git a/src/backend/anastasis-httpd_truth.c
b/src/backend/anastasis-httpd_truth.c
index e229d2a..9c8fe88 100644
--- a/src/backend/anastasis-httpd_truth.c
+++ b/src/backend/anastasis-httpd_truth.c
@@ -31,6 +31,13 @@
#include <taler/taler_merchant_service.h>
#include <taler/taler_json_lib.h>
+/**
+ * How long do we hold an HTTP client connection if
+ * we are awaiting payment before giving up?
+ */
+#define CHECK_PAYMENT_GENERIC_TIMEOUT GNUNET_TIME_relative_multiply ( \
+ GNUNET_TIME_UNIT_MINUTES, 30)
+
struct GetContext
{
/**
@@ -568,7 +575,7 @@ handle_database_error (struct GetContext *gc,
case ANASTASIS_DB_STATUS_HARD_ERROR:
case ANASTASIS_DB_STATUS_SOFT_ERROR:
GNUNET_break (0);
- return TALER_MHD_reply_with_error (puc->con,
+ return TALER_MHD_reply_with_error (gc->connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
NULL);
@@ -778,10 +785,10 @@ AH_handler_truth_get (struct MHD_Connection *connection,
TALER_B2S (&gc->payment_identifier));
qs = db->check_challenge_payment (db->cls,
- &puc->payment_identifier,
+ &gc->payment_identifier,
&paid);
if (qs < 0)
- return handle_database_error (puc,
+ return handle_database_error (gc,
qs);
if ((qs >= 0) && (! paid))
@@ -834,12 +841,12 @@ AH_handler_truth_get (struct MHD_Connection *connection,
{
qs = db->record_challenge_payment (db->cls,
&truth_public_key,
- &puc->payment_identifier,
+ &gc->payment_identifier,
&gc->challenge_cost);
if (qs >= 0)
{
qs = db->update_challenge_payment (db->cls,
- truth_public_key,
+ &truth_public_key,
&gc->payment_identifier);
}
if (qs < 0)
@@ -856,214 +863,215 @@ AH_handler_truth_get (struct MHD_Connection *connection,
GNUNET_YES);
}
}
- /* check if the client insists on paying */
- {
- const char *order_req;
+ }
+ /* check if the client insists on paying */
+ {
+ const char *order_req;
- order_req = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- "pay");
- if (NULL != order_req)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Payment requested, starting payment process\n");
- return begin_payment (gc,
- GNUNET_YES);
- }
+ order_req = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "pay");
+ if (NULL != order_req)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Payment requested, starting payment process\n");
+ return begin_payment (gc,
+ GNUNET_YES);
}
+ }
- if (0 == strcmp ("question",
- method))
+ if (0 == strcmp ("question",
+ method))
+ {
+ if (NULL == challenge_response_s)
{
- if (NULL == challenge_response_s)
- {
- // FIXME: queue PROPER reply...
- GNUNET_free (decrypted_truth);
- return MHD_NO;
- }
+ // FIXME: queue PROPER reply...
+ GNUNET_free (decrypted_truth);
+ return MHD_NO;
+ }
- GNUNET_CRYPTO_hash_from_string (challenge_response_s,
- &challenge_response);
+ GNUNET_CRYPTO_hash_from_string (challenge_response_s,
+ &challenge_response);
- if (0 != GNUNET_memcmp (&challenge_response,
- decrypted_truth))
- {
- GNUNET_break (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- // FIXME: find error code
- TALER_EC_SYNC_BAD_IF_MATCH,
- "Authentication failed"); // FIXME:
How much should we tell?
- }
- else
- {
- return return_key_share (&truth_public_key,
- connection);
- }
+ if (0 != GNUNET_memcmp (&challenge_response,
+ decrypted_truth))
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ // FIXME: find error code
+ TALER_EC_SYNC_BAD_IF_MATCH,
+ "Authentication failed"); // FIXME:
How much should we tell?
}
-
- /* Not security question, check for answer in DB */
- if (NULL != challenge_response_s)
+ else
{
- enum ANASTASIS_DB_QueryStatus qs;
- unsigned long long code;
- char dummy;
-
- if (1 != sscanf (challenge_response_s,
- "%llu%c",
- &code,
- &dummy))
- {
- // FIXME: queue PROPER reply...
- GNUNET_free (decrypted_truth);
- return MHD_NO;
- }
+ return return_key_share (&truth_public_key,
+ connection);
+ }
+ }
- qs = db->verify_challenge_code (db->cls,
- &truth_public_key,
- code);
+ /* Not security question, check for answer in DB */
+ if (NULL != challenge_response_s)
+ {
+ enum ANASTASIS_DB_QueryStatus qs;
+ unsigned long long code;
+ char dummy;
- switch (qs)
- {
- case ANASTASIS_DB_STATUS_HARD_ERROR:
- GNUNET_free (decrypted_truth);
- return MHD_NO;
- case ANASTASIS_DB_STATUS_SOFT_ERROR:
- GNUNET_free (decrypted_truth);
- return MHD_NO;
- case ANASTASIS_DB_STATUS_NO_RESULTS:
- GNUNET_free (decrypted_truth);
- return MHD_NO;
- case ANASTASIS_DB_STATUS_VALID_CODE_STORED:
- break;
- default:
- GNUNET_free (decrypted_truth);
- return MHD_NO;
- }
+ if (1 != sscanf (challenge_response_s,
+ "%llu%c",
+ &code,
+ &dummy))
+ {
+ // FIXME: queue PROPER reply...
+ GNUNET_free (decrypted_truth);
+ return MHD_NO;
+ }
- return return_key_share (&truth_public_key,
- connection);
+ qs = db->verify_challenge_code (db->cls,
+ &truth_public_key,
+ code);
+
+ switch (qs)
+ {
+ case ANASTASIS_DB_STATUS_HARD_ERROR:
+ GNUNET_free (decrypted_truth);
+ return MHD_NO;
+ case ANASTASIS_DB_STATUS_SOFT_ERROR:
+ GNUNET_free (decrypted_truth);
+ return MHD_NO;
+ case ANASTASIS_DB_STATUS_NO_RESULTS:
+ GNUNET_free (decrypted_truth);
+ return MHD_NO;
+ case ANASTASIS_DB_STATUS_VALID_CODE_STORED:
+ break;
+ default:
+ GNUNET_free (decrypted_truth);
+ return MHD_NO;
}
- /* Not security question and no answer: use plugin to generate challenge!
*/
+ return return_key_share (&truth_public_key,
+ connection);
+ }
+
+ /* Not security question and no answer: use plugin to generate challenge! */
+ {
+ struct ANASTASIS_AuthorizationPlugin *authorization;
+ enum GNUNET_GenericReturnValue ret;
+ struct ANASTASIS_AUTHORIZATION_State *as;
+ enum ANASTASIS_AUTHORIZATION_Result aret;
+ enum ANASTASIS_DB_QueryStatus qs;
+ struct GNUNET_TIME_Relative challenge_expiration;
+ challenge_expiration = GNUNET_TIME_UNIT_HOURS;
+
+ authorization = ANASTASIS_authorization_plugin_load (method);
+ if (NULL == authorization)
{
- struct ANASTASIS_AuthorizationPlugin *authorization;
- enum GNUNET_GenericReturnValue ret;
- struct ANASTASIS_AUTHORIZATION_State *as;
- enum ANASTASIS_AUTHORIZATION_Result aret;
- enum ANASTASIS_DB_QueryStatus qs;
- struct GNUNET_TIME_Relative challenge_expiration;
- challenge_expiration = GNUNET_TIME_UNIT_HOURS;
-
- authorization = ANASTASIS_authorization_plugin_load (method);
- if (NULL == authorization)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Plugin not found: %s",method);
- GNUNET_free (decrypted_truth);
- return MHD_NO;
- }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Plugin not found: %s",method);
+ GNUNET_free (decrypted_truth);
+ return MHD_NO;
+ }
- ret = authorization->validate (authorization->cls,
- connection,
- decrypted_truth,
- decrypted_truth_size);
+ ret = authorization->validate (authorization->cls,
+ connection,
+ decrypted_truth,
+ decrypted_truth_size);
- switch (ret)
- {
- case GNUNET_OK:
- /* data valid, continued below */
- break;
- case GNUNET_NO:
- /* data invalid, reply was queued */
- GNUNET_free (decrypted_truth);
- return MHD_YES;
- case GNUNET_SYSERR:
- /* data invalid, reply was NOT queued */
- GNUNET_free (decrypted_truth);
- return MHD_NO;
- }
- // FIXME:
- // RANDOM! -- or from DB if recent one in DB!
- uint64_t code = 42;
- // FIXME TIME where to put this?
- // FIXME retry counter where to put it?
- qs = db->store_challenge_code (db->cls,
- &truth_public_key,
- code,
- challenge_expiration,
- 3);
-
- switch (qs)
- {
- case ANASTASIS_DB_STATUS_HARD_ERROR:
- /* data invalid, reply was NOT queued */
- GNUNET_free (decrypted_truth);
- return MHD_NO;
- case ANASTASIS_DB_STATUS_SOFT_ERROR:
- /* data invalid, reply was NOT queued */
- GNUNET_free (decrypted_truth);
- return MHD_NO;
- case ANASTASIS_DB_STATUS_VALID_CODE_STORED:
- /*FIXME already code stored message */
- return MHD_NO;
- case ANASTASIS_DB_STATUS_SUCCESS_ONE_RESULT:
- /*challengecode was stored successfully*/
- break;
- default:
- GNUNET_free (decrypted_truth);
- return MHD_NO;
- }
+ switch (ret)
+ {
+ case GNUNET_OK:
+ /* data valid, continued below */
+ break;
+ case GNUNET_NO:
+ /* data invalid, reply was queued */
+ GNUNET_free (decrypted_truth);
+ return MHD_YES;
+ case GNUNET_SYSERR:
+ /* data invalid, reply was NOT queued */
+ GNUNET_free (decrypted_truth);
+ return MHD_NO;
+ }
+ // FIXME:
+ // RANDOM! -- or from DB if recent one in DB!
+ uint64_t code = 42;
+ // FIXME TIME where to put this?
+ // FIXME retry counter where to put it?
+ qs = db->store_challenge_code (db->cls,
+ &truth_public_key,
+ code,
+ challenge_expiration,
+ 3);
- as = authorization->start (authorization->cls,
- &truth_public_key,
- code,
- decrypted_truth,
- decrypted_truth_size);
+ switch (qs)
+ {
+ case ANASTASIS_DB_STATUS_HARD_ERROR:
+ /* data invalid, reply was NOT queued */
GNUNET_free (decrypted_truth);
- if (NULL == as)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- ("AUTHORIZATION START FAILED"));
- // FIXME: queue PROPER reply...
- return MHD_NO;
- }
- gc = GNUNET_new (struct GetContext);
- gc->connection = connection;
- gc->authorization = authorization;
- gc->as = as;
- hc->ctx = gc;
- hc->cc = &request_done;
- GNUNET_CONTAINER_DLL_insert (gc_head,
- gc_tail,
- gc);
- aret = authorization->process (as,
- connection);
- switch (aret)
- {
- case ANASTASIS_AUTHORIZATION_RES_SUCCESS:
- /* all good, challenge sent! */
- // FIXME: mark in DB that we did it (now, for
code_retransmission_frequency!)
- break;
- case ANASTASIS_AUTHORIZATION_RES_FAILED:
- /* sending challenge failed */
- // FIXME: give at least a refund!?
- break;
- case ANASTASIS_AUTHORIZATION_RES_SUSPENDED:
- /* we have been suspended, see you later */
- return MHD_YES;
- case ANASTASIS_AUTHORIZATION_RES_SUCCESS_REPLY_FAILED:
- /* Challenge sent successfully */
- // FIXME: mark in DB that we did it (now, for
code_retransmission_frequency!)
- authorization->cleanup (gc->as);
- return MHD_NO;
- case ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED:
- /* failure to queue reply, kill connection */
- authorization->cleanup (gc->as);
- return MHD_NO;
- }
- authorization->cleanup (gc->as);
- gc->as = NULL;
+ return MHD_NO;
+ case ANASTASIS_DB_STATUS_SOFT_ERROR:
+ /* data invalid, reply was NOT queued */
+ GNUNET_free (decrypted_truth);
+ return MHD_NO;
+ case ANASTASIS_DB_STATUS_VALID_CODE_STORED:
+ /*FIXME already code stored message */
+ return MHD_NO;
+ case ANASTASIS_DB_STATUS_SUCCESS_ONE_RESULT:
+ /*challengecode was stored successfully*/
+ break;
+ default:
+ GNUNET_free (decrypted_truth);
+ return MHD_NO;
+ }
+
+ as = authorization->start (authorization->cls,
+ &truth_public_key,
+ code,
+ decrypted_truth,
+ decrypted_truth_size);
+ GNUNET_free (decrypted_truth);
+ if (NULL == as)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ ("AUTHORIZATION START FAILED"));
+ // FIXME: queue PROPER reply...
+ return MHD_NO;
+ }
+ gc = GNUNET_new (struct GetContext);
+ gc->connection = connection;
+ gc->authorization = authorization;
+ gc->as = as;
+ hc->ctx = gc;
+ hc->cc = &request_done;
+ GNUNET_CONTAINER_DLL_insert (gc_head,
+ gc_tail,
+ gc);
+ aret = authorization->process (as,
+ connection);
+ switch (aret)
+ {
+ case ANASTASIS_AUTHORIZATION_RES_SUCCESS:
+ /* all good, challenge sent! */
+ // FIXME: mark in DB that we did it (now, for
code_retransmission_frequency!)
+ break;
+ case ANASTASIS_AUTHORIZATION_RES_FAILED:
+ /* sending challenge failed */
+ // FIXME: give at least a refund!?
+ break;
+ case ANASTASIS_AUTHORIZATION_RES_SUSPENDED:
+ /* we have been suspended, see you later */
return MHD_YES;
+ case ANASTASIS_AUTHORIZATION_RES_SUCCESS_REPLY_FAILED:
+ /* Challenge sent successfully */
+ // FIXME: mark in DB that we did it (now, for
code_retransmission_frequency!)
+ authorization->cleanup (gc->as);
+ return MHD_NO;
+ case ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED:
+ /* failure to queue reply, kill connection */
+ authorization->cleanup (gc->as);
+ return MHD_NO;
}
+ authorization->cleanup (gc->as);
+ gc->as = NULL;
+ return MHD_YES;
}
+}
diff --git a/src/include/anastasis_service.h b/src/include/anastasis_service.h
index 6b24934..4da46e2 100644
--- a/src/include/anastasis_service.h
+++ b/src/include/anastasis_service.h
@@ -241,7 +241,7 @@ struct ANASTASIS_ChallengeRunDetails
{
const char *response_string;
const char *payment_request;
-}
+};
typedef void
@@ -551,7 +551,7 @@ ANASTASIS_keyshare_lookup (struct GNUNET_CURL_Context *ctx,
ANASTASIS_PaymentSecretP *payment_secret,
const char *answer,
ANASTASIS_KeyShareLookupCallback cb,
- void *cb_cls)
+ void *cb_cls);
/**
* Cancel a GET /truth request.
diff --git a/src/lib/anastasis.c b/src/lib/anastasis.c
index 8528d60..8805364 100644
--- a/src/lib/anastasis.c
+++ b/src/lib/anastasis.c
@@ -228,6 +228,23 @@ struct ANASTASIS_Challenge
* Cost for authentication
*/
struct TALER_Amount cost;
+
+ /**
+ * Payment identifier.
+ */
+ struct ANASTASIS_PaymentSecretP payment_secret;
+
+ /**
+ * Payment order ID we got back, if any. Otherwise NULL.
+ */
+ char *payment_order_id;
+
+ /**
+ * Payment order ID we are to provide in the request, may be NULL.
+ */
+ const char *payment_order_req;
+
+ int payment_requested;
};
/**
@@ -403,6 +420,8 @@ ANASTASIS_challenge_answer (struct GNUNET_CURL_Context *ctx,
c->url,
&c->truth_public_key,
&c->truth_key,
+ c->payment_requested,
+ &c->payment_secret,
str,
&keyshare_lookup_cb,
c);
@@ -414,6 +433,8 @@ ANASTASIS_challenge_answer (struct GNUNET_CURL_Context *ctx,
c->url,
&c->truth_public_key,
&c->truth_key,
+ c->payment_requested,
+ &c->payment_secret,
answer_str,
&keyshare_lookup_cb,
c);
diff --git a/src/lib/anastasis_api_keyshare_lookup.c
b/src/lib/anastasis_api_keyshare_lookup.c
index b3c96c0..6f59623 100644
--- a/src/lib/anastasis_api_keyshare_lookup.c
+++ b/src/lib/anastasis_api_keyshare_lookup.c
@@ -284,29 +284,30 @@ ANASTASIS_keyshare_lookup (struct GNUNET_CURL_Context
*ctx,
return NULL;
}
job_headers = ext;
- }
- /* Setup Payment-Identifier header */
- if (NULL != payment_secret)
- {
- char *paid_order_id;
- paid_order_id = GNUNET_STRINGS_data_to_string_alloc (
- payment_secret,
- sizeof (*payment_secret));
- GNUNET_asprintf (&hdr,
- "Payment-Identifier: %s",
- paid_order_id);
- GNUNET_free (paid_order_id);
- ext = curl_slist_append (job_headers,
- hdr);
- GNUNET_free (hdr);
- if (NULL == ext)
+ /* Setup Payment-Identifier header */
+ if (NULL != payment_secret)
{
- GNUNET_break (0);
- curl_slist_free_all (job_headers);
- return NULL;
+ char *paid_order_id;
+
+ paid_order_id = GNUNET_STRINGS_data_to_string_alloc (
+ payment_secret,
+ sizeof (*payment_secret));
+ GNUNET_asprintf (&hdr,
+ "Payment-Identifier: %s",
+ paid_order_id);
+ GNUNET_free (paid_order_id);
+ ext = curl_slist_append (job_headers,
+ hdr);
+ GNUNET_free (hdr);
+ if (NULL == ext)
+ {
+ GNUNET_break (0);
+ curl_slist_free_all (job_headers);
+ return NULL;
+ }
+ job_headers = ext;
}
- job_headers = ext;
}
kslo = GNUNET_new (struct ANASTASIS_KeyShareLookupOperation);
kslo->ctx = ctx;
diff --git a/src/lib/testing_api_cmd_challenge_run.c
b/src/lib/testing_api_cmd_challenge_run.c
index f1b9231..47ce2ad 100644
--- a/src/lib/testing_api_cmd_challenge_run.c
+++ b/src/lib/testing_api_cmd_challenge_run.c
@@ -139,7 +139,7 @@ challenge_run_cb (void *cls,
"Did not find `%s' in `%s'\n",
"/-/-/",
crd->payment_request);
- TALER_TESTING_interpreter_fail (pss->is);
+ TALER_TESTING_interpreter_fail (crs->is);
/* NOTE: The above is a simplifying assumption for the
test-logic, hitting this code merely means that
the assumptions for the test (i.e. no instance) are
@@ -153,19 +153,19 @@ challenge_run_cb (void *cls,
crs->payment_order_id = GNUNET_strdup (&m[strlen ("/-/-/")]);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Order ID from Anastasis service is `%s'\n",
- pss->payment_order_id);
+ crs->payment_order_id);
}
FILE *file;
crs->code = malloc (sizeof(char) * 22);
- file = fopen (response_string, "r");
+ file = fopen (crd->response_string, "r");
if (file == NULL)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"could not find file: %s to command %s in %s:%u\n",
- response_string,
+ crd->response_string,
crs->is->commands[crs->is->ip].label,
__FILE__,
__LINE__);
@@ -197,9 +197,9 @@ challenge_run_create_traits (void *cls,
ANASTASIS_TESTING_make_trait_code (0,
crs->code),
TALER_TESTING_make_trait_claim_token (0,
- &pss->token),
+ &crs->token),
TALER_TESTING_make_trait_order_id (0,
- pss->payment_order_id),
+ crs->payment_order_id),
TALER_TESTING_trait_end ()
};
diff --git a/src/lib/testing_api_cmd_keyshare_lookup.c
b/src/lib/testing_api_cmd_keyshare_lookup.c
index dcd7796..7427925 100644
--- a/src/lib/testing_api_cmd_keyshare_lookup.c
+++ b/src/lib/testing_api_cmd_keyshare_lookup.c
@@ -79,7 +79,7 @@ struct KeyShareLookupState
/**
* Payment secret used for the payment
*/
- const struct ANASTASIS_PaymentSecretP payment_secret;
+ struct ANASTASIS_PaymentSecretP *payment_secret;
/**
* if payment is needed or free
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-anastasis] branch master updated: errors,
gnunet <=