summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2021-08-19 13:41:30 +0200
committerChristian Grothoff <christian@grothoff.org>2021-08-19 13:41:30 +0200
commit81d0e570be0db784e98fdb7ad63f9b65c6745be3 (patch)
tree578a91bd888abfac827c23ba2933174c7d2341de /src
parent87bc2f469bf120bbd57e98a0a8ea46e80de84927 (diff)
downloadanastasis-81d0e570be0db784e98fdb7ad63f9b65c6745be3.tar.gz
anastasis-81d0e570be0db784e98fdb7ad63f9b65c6745be3.tar.bz2
anastasis-81d0e570be0db784e98fdb7ad63f9b65c6745be3.zip
-implement DB triggers and check for inbound wire transfers in IBAN plugin
Diffstat (limited to 'src')
-rw-r--r--src/authorization/Makefile.am3
-rw-r--r--src/authorization/anastasis-helper-authorization-iban.c50
-rw-r--r--src/authorization/anastasis_authorization_plugin_iban.c134
-rw-r--r--src/authorization/iban.c43
-rw-r--r--src/authorization/iban.h2
5 files changed, 224 insertions, 8 deletions
diff --git a/src/authorization/Makefile.am b/src/authorization/Makefile.am
index c2ae0a5..0687129 100644
--- a/src/authorization/Makefile.am
+++ b/src/authorization/Makefile.am
@@ -15,7 +15,7 @@ pkgdata_DATA = \
EXTRA_DIST = \
$(pkgdata_DATA) \
- iban.h
+ iban.h iban.c
if USE_COVERAGE
@@ -32,6 +32,7 @@ anastasis_helper_authorization_iban_LDADD = \
$(top_builddir)/src/stasis/libanastasisdb.la \
$(top_builddir)/src/authorization/libanastasiseufin/libanastasiseufin.la \
$(top_builddir)/src/util/libanastasisutil.la \
+ -ltalermhd \
-ltalerutil \
-lgnunetcurl \
-lgnunetutil \
diff --git a/src/authorization/anastasis-helper-authorization-iban.c b/src/authorization/anastasis-helper-authorization-iban.c
index 0d3200a..d509c0e 100644
--- a/src/authorization/anastasis-helper-authorization-iban.c
+++ b/src/authorization/anastasis-helper-authorization-iban.c
@@ -17,10 +17,6 @@
* @file anastasis-helper-authorization-iban.c
* @brief Process that watches for wire transfers to Anastasis bank account
* @author Christian Grothoff
- *
- * TODO:
- * - needs to add DB triggers to notify main service of inbound activity
- * - needs man page
*/
#include "platform.h"
#include "anastasis_eufin_lib.h"
@@ -31,6 +27,7 @@
#include <jansson.h>
#include <pthread.h>
#include <microhttpd.h>
+#include "iban.h"
/**
* How long to wait for an HTTP reply if there
@@ -108,6 +105,37 @@ static struct GNUNET_SCHEDULER_Task *task;
/**
+ * Notify anastasis-http that we received @a amount
+ * from @a sender_account_uri with @a code.
+ *
+ * @param sender_account_uri payto:// URI of the sending account
+ * @param code numeric code used in the wire transfer subject
+ * @param amount the amount that was wired
+ */
+static void
+notify (const char *sender_account_uri,
+ uint64_t code,
+ const struct TALER_Amount *amount)
+{
+ struct IbanEventP ev = {
+ .header.type = htons (TALER_DBEVENT_ANASTASIS_AUTH_IBAN_TRANSFER),
+ .header.size = htons (sizeof (ev)),
+ .code = GNUNET_htonll (code)
+ };
+ const char *as;
+
+ GNUNET_CRYPTO_hash (sender_account_uri,
+ strlen (sender_account_uri),
+ &ev.debit_iban_hash);
+ as = TALER_amount2s (amount);
+ db_plugin->event_notify (db_plugin->cls,
+ &ev.header,
+ as,
+ strlen (as));
+}
+
+
+/**
* We're being aborted with CTRL-C (or SIGTERM). Shut down.
*
* @param cls closure
@@ -152,6 +180,9 @@ static void
find_transfers (void *cls);
+#include "iban.c"
+
+
/**
* Callbacks of this type are used to serve the result of asking
* the bank for the transaction history.
@@ -232,6 +263,17 @@ history_cb (void *cls,
break;
}
latest_row_off = serial_id;
+ {
+ uint64_t code;
+
+ if (GNUNET_OK !=
+ extract_code (details->wire_subject,
+ &code))
+ return GNUNET_OK;
+ notify (details->debit_account_uri,
+ code,
+ &details->amount);
+ }
return GNUNET_OK;
}
diff --git a/src/authorization/anastasis_authorization_plugin_iban.c b/src/authorization/anastasis_authorization_plugin_iban.c
index eee8e7e..4f43d3f 100644
--- a/src/authorization/anastasis_authorization_plugin_iban.c
+++ b/src/authorization/anastasis_authorization_plugin_iban.c
@@ -29,6 +29,16 @@
#include "iban.h"
/**
+ * How long is a code valid once generated? Very long
+ * here as we do not want to refuse authentication
+ * just because the user took a while to execute the
+ * wire transfer (and then get back to their recovery
+ * operation).
+ */
+#define CODE_VALIDITY_PERIOD GNUNET_TIME_UNIT_MONTHS
+
+
+/**
* Saves the State of a authorization plugin.
*/
struct IBAN_Context
@@ -367,7 +377,116 @@ respond_with_challenge (struct ANASTASIS_AUTHORIZATION_State *as,
return ANASTASIS_AUTHORIZATION_RES_SUCCESS_REPLY_FAILED;
return ANASTASIS_AUTHORIZATION_RES_SUCCESS;
}
+}
+
+
+#include "iban.c"
+
+
+/**
+ * Check if the @a wire_subject matches the challenge in the context
+ * and if the @a amount is sufficient. If so, return true.
+ *
+ * @param cls a `const struct ANASTASIS_AUTHORIZATION_State *`
+ * @param amount the amount that was transferred
+ * @param wire_subject a wire subject we received
+ * @return true if the wire transfer satisfied the check
+ */
+static bool
+check_payment_ok (void *cls,
+ const struct TALER_Amount *amount,
+ const char *wire_subject)
+{
+ const struct ANASTASIS_AUTHORIZATION_State *as = cls;
+ struct IBAN_Context *ctx = as->ctx;
+ uint64_t code;
+
+ if (GNUNET_OK !=
+ extract_code (wire_subject,
+ &code))
+ return false;
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (&ctx->expected_amount,
+ amount))
+ {
+ /* currency wrong!? */
+ GNUNET_break (0);
+ return false;
+ }
+ if (1 ==
+ TALER_amount_cmp (&ctx->expected_amount,
+ amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Amount `%s' insufficient for authorization\n",
+ TALER_amount2s (amount));
+ return false;
+ }
+ return (code == as->code);
+}
+
+/**
+ * Check if we have received a wire transfer with a subject
+ * authorizing the disclosure of the credential in the meantime.
+ *
+ * @param as state to check for
+ * @return WTS_SUCCESS if a transfer was received,
+ * WTS_NOT_READY if no transfer was received,
+ * WTS_FAILED_WITH_REPLY if we had an internal error and queued a reply
+ * WTS_FAILED_WITHOUT_REPLY if we had an internal error and failed to queue a reply
+ */
+static enum
+{
+ WTS_SUCCESS,
+ WTS_NOT_READY,
+ WTS_FAILED_WITH_REPLY,
+ WTS_FAILED_WITHOUT_REPLY
+}
+test_wire_transfers (struct ANASTASIS_AUTHORIZATION_State *as)
+{
+ struct IBAN_Context *ctx = as->ctx;
+ struct ANASTASIS_DatabasePlugin *db = ctx->ac->db;
+ enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Absolute limit;
+ char *debit_account_uri;
+
+ now = GNUNET_TIME_absolute_get ();
+ limit = GNUNET_TIME_absolute_subtract (now,
+ CODE_VALIDITY_PERIOD);
+ GNUNET_asprintf (&debit_account_uri,
+ "payto://iban/%s",
+ as->iban_number);
+ qs = db->test_auth_iban_payment (
+ db->cls,
+ debit_account_uri,
+ limit,
+ &check_payment_ok,
+ as);
+ GNUNET_free (debit_account_uri);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ return (MHD_YES ==
+ TALER_MHD_reply_with_error (as->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL))
+ ? WTS_FAILED_WITH_REPLY
+ : WTS_FAILED_WITHOUT_REPLY;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ return WTS_NOT_READY;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+ qs = db->mark_challenge_code_satisfied (
+ db->cls,
+ &as->truth_uuid,
+ as->code);
+ GNUNET_break (qs > 0);
+ return WTS_SUCCESS;
}
@@ -423,6 +542,17 @@ iban_process (struct ANASTASIS_AUTHORIZATION_State *as,
return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
return ANASTASIS_AUTHORIZATION_RES_FAILED;
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ switch (test_wire_transfers (as))
+ {
+ case WTS_SUCCESS:
+ return ANASTASIS_AUTHORIZATION_RES_FINISHED;
+ case WTS_NOT_READY:
+ break; /* continue below */
+ case WTS_FAILED_WITH_REPLY:
+ return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ case WTS_FAILED_WITHOUT_REPLY:
+ return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
+ }
if (GNUNET_TIME_absolute_is_future (timeout))
{
as->connection = connection;
@@ -529,9 +659,9 @@ libanastasis_plugin_authorization_iban_init (void *cls)
ctx->ac = ac;
plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin);
plugin->payment_plugin_managed = true;
- plugin->code_validity_period = GNUNET_TIME_UNIT_MONTHS;
+ plugin->code_validity_period = CODE_VALIDITY_PERIOD;
plugin->code_rotation_period = GNUNET_TIME_UNIT_WEEKS;
- plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_FOREVER_REL;
+ plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_FOREVER_REL; /* not applicable */
plugin->cls = ctx;
plugin->validate = &iban_validate;
plugin->start = &iban_start;
diff --git a/src/authorization/iban.c b/src/authorization/iban.c
new file mode 100644
index 0000000..9547790
--- /dev/null
+++ b/src/authorization/iban.c
@@ -0,0 +1,43 @@
+/**
+ * Extract a numeric @a code from a @a wire_subject.
+ * Also checks that the @a wire_subject contains the
+ * string "anastasis".
+ *
+ * @param wire_subject wire subject to extract @a code from
+ * @param[out] code where to write the extracted code
+ * @return #GNUNET_OK if a @a code was extracted
+ */
+static enum GNUNET_GenericReturnValue
+extract_code (const char *wire_subject,
+ uint64_t *code)
+{
+ unsigned long long c;
+ const char *pos;
+
+ if (0 !=
+ strcasestr (wire_subject,
+ "anastasis"))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Keyword 'anastasis' missing in subject `%s', ignoring transfer\n",
+ wire_subject);
+ return GNUNET_SYSERR;
+ }
+ pos = wire_subject;
+ while ( ('\0' != *pos) &&
+ (! isdigit ((int) *pos)) )
+ pos++;
+ if (1 !=
+ sscanf (pos,
+ "%llu",
+ &c))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Did not find any code number in subject `%s', ignoring transfer\n",
+ wire_subject);
+ return GNUNET_SYSERR;
+ }
+
+ *code = (uint64_t) c;
+ return GNUNET_OK;
+}
diff --git a/src/authorization/iban.h b/src/authorization/iban.h
index c95c00d..70db7ea 100644
--- a/src/authorization/iban.h
+++ b/src/authorization/iban.h
@@ -32,7 +32,7 @@ GNUNET_NETWORK_STRUCT_BEGIN
struct IbanEventP
{
/**
- * Header of type #TALER_DBEVENT_TYPE_ANASTASIS_AUTH_IBAN_TRANSFER.
+ * Header of type #TALER_DBEVENT_ANASTASIS_AUTH_IBAN_TRANSFER.
*/
struct GNUNET_DB_EventHeaderP header;