aboutsummaryrefslogtreecommitdiff
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
parent87bc2f469bf120bbd57e98a0a8ea46e80de84927 (diff)
downloadanastasis-81d0e570be0db784e98fdb7ad63f9b65c6745be3.tar.gz
anastasis-81d0e570be0db784e98fdb7ad63f9b65c6745be3.zip
-implement DB triggers and check for inbound wire transfers in IBAN plugin
-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 = \
15 15
16EXTRA_DIST = \ 16EXTRA_DIST = \
17 $(pkgdata_DATA) \ 17 $(pkgdata_DATA) \
18 iban.h 18 iban.h iban.c
19 19
20 20
21if USE_COVERAGE 21if USE_COVERAGE
@@ -32,6 +32,7 @@ anastasis_helper_authorization_iban_LDADD = \
32 $(top_builddir)/src/stasis/libanastasisdb.la \ 32 $(top_builddir)/src/stasis/libanastasisdb.la \
33 $(top_builddir)/src/authorization/libanastasiseufin/libanastasiseufin.la \ 33 $(top_builddir)/src/authorization/libanastasiseufin/libanastasiseufin.la \
34 $(top_builddir)/src/util/libanastasisutil.la \ 34 $(top_builddir)/src/util/libanastasisutil.la \
35 -ltalermhd \
35 -ltalerutil \ 36 -ltalerutil \
36 -lgnunetcurl \ 37 -lgnunetcurl \
37 -lgnunetutil \ 38 -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 @@
17 * @file anastasis-helper-authorization-iban.c 17 * @file anastasis-helper-authorization-iban.c
18 * @brief Process that watches for wire transfers to Anastasis bank account 18 * @brief Process that watches for wire transfers to Anastasis bank account
19 * @author Christian Grothoff 19 * @author Christian Grothoff
20 *
21 * TODO:
22 * - needs to add DB triggers to notify main service of inbound activity
23 * - needs man page
24 */ 20 */
25#include "platform.h" 21#include "platform.h"
26#include "anastasis_eufin_lib.h" 22#include "anastasis_eufin_lib.h"
@@ -31,6 +27,7 @@
31#include <jansson.h> 27#include <jansson.h>
32#include <pthread.h> 28#include <pthread.h>
33#include <microhttpd.h> 29#include <microhttpd.h>
30#include "iban.h"
34 31
35/** 32/**
36 * How long to wait for an HTTP reply if there 33 * How long to wait for an HTTP reply if there
@@ -108,6 +105,37 @@ static struct GNUNET_SCHEDULER_Task *task;
108 105
109 106
110/** 107/**
108 * Notify anastasis-http that we received @a amount
109 * from @a sender_account_uri with @a code.
110 *
111 * @param sender_account_uri payto:// URI of the sending account
112 * @param code numeric code used in the wire transfer subject
113 * @param amount the amount that was wired
114 */
115static void
116notify (const char *sender_account_uri,
117 uint64_t code,
118 const struct TALER_Amount *amount)
119{
120 struct IbanEventP ev = {
121 .header.type = htons (TALER_DBEVENT_ANASTASIS_AUTH_IBAN_TRANSFER),
122 .header.size = htons (sizeof (ev)),
123 .code = GNUNET_htonll (code)
124 };
125 const char *as;
126
127 GNUNET_CRYPTO_hash (sender_account_uri,
128 strlen (sender_account_uri),
129 &ev.debit_iban_hash);
130 as = TALER_amount2s (amount);
131 db_plugin->event_notify (db_plugin->cls,
132 &ev.header,
133 as,
134 strlen (as));
135}
136
137
138/**
111 * We're being aborted with CTRL-C (or SIGTERM). Shut down. 139 * We're being aborted with CTRL-C (or SIGTERM). Shut down.
112 * 140 *
113 * @param cls closure 141 * @param cls closure
@@ -152,6 +180,9 @@ static void
152find_transfers (void *cls); 180find_transfers (void *cls);
153 181
154 182
183#include "iban.c"
184
185
155/** 186/**
156 * Callbacks of this type are used to serve the result of asking 187 * Callbacks of this type are used to serve the result of asking
157 * the bank for the transaction history. 188 * the bank for the transaction history.
@@ -232,6 +263,17 @@ history_cb (void *cls,
232 break; 263 break;
233 } 264 }
234 latest_row_off = serial_id; 265 latest_row_off = serial_id;
266 {
267 uint64_t code;
268
269 if (GNUNET_OK !=
270 extract_code (details->wire_subject,
271 &code))
272 return GNUNET_OK;
273 notify (details->debit_account_uri,
274 code,
275 &details->amount);
276 }
235 return GNUNET_OK; 277 return GNUNET_OK;
236} 278}
237 279
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 @@
29#include "iban.h" 29#include "iban.h"
30 30
31/** 31/**
32 * How long is a code valid once generated? Very long
33 * here as we do not want to refuse authentication
34 * just because the user took a while to execute the
35 * wire transfer (and then get back to their recovery
36 * operation).
37 */
38#define CODE_VALIDITY_PERIOD GNUNET_TIME_UNIT_MONTHS
39
40
41/**
32 * Saves the State of a authorization plugin. 42 * Saves the State of a authorization plugin.
33 */ 43 */
34struct IBAN_Context 44struct IBAN_Context
@@ -367,7 +377,116 @@ respond_with_challenge (struct ANASTASIS_AUTHORIZATION_State *as,
367 return ANASTASIS_AUTHORIZATION_RES_SUCCESS_REPLY_FAILED; 377 return ANASTASIS_AUTHORIZATION_RES_SUCCESS_REPLY_FAILED;
368 return ANASTASIS_AUTHORIZATION_RES_SUCCESS; 378 return ANASTASIS_AUTHORIZATION_RES_SUCCESS;
369 } 379 }
380}
381
382
383#include "iban.c"
384
385
386/**
387 * Check if the @a wire_subject matches the challenge in the context
388 * and if the @a amount is sufficient. If so, return true.
389 *
390 * @param cls a `const struct ANASTASIS_AUTHORIZATION_State *`
391 * @param amount the amount that was transferred
392 * @param wire_subject a wire subject we received
393 * @return true if the wire transfer satisfied the check
394 */
395static bool
396check_payment_ok (void *cls,
397 const struct TALER_Amount *amount,
398 const char *wire_subject)
399{
400 const struct ANASTASIS_AUTHORIZATION_State *as = cls;
401 struct IBAN_Context *ctx = as->ctx;
402 uint64_t code;
403
404 if (GNUNET_OK !=
405 extract_code (wire_subject,
406 &code))
407 return false;
408 if (GNUNET_OK !=
409 TALER_amount_cmp_currency (&ctx->expected_amount,
410 amount))
411 {
412 /* currency wrong!? */
413 GNUNET_break (0);
414 return false;
415 }
416 if (1 ==
417 TALER_amount_cmp (&ctx->expected_amount,
418 amount))
419 {
420 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
421 "Amount `%s' insufficient for authorization\n",
422 TALER_amount2s (amount));
423 return false;
424 }
425 return (code == as->code);
426}
427
370 428
429/**
430 * Check if we have received a wire transfer with a subject
431 * authorizing the disclosure of the credential in the meantime.
432 *
433 * @param as state to check for
434 * @return WTS_SUCCESS if a transfer was received,
435 * WTS_NOT_READY if no transfer was received,
436 * WTS_FAILED_WITH_REPLY if we had an internal error and queued a reply
437 * WTS_FAILED_WITHOUT_REPLY if we had an internal error and failed to queue a reply
438 */
439static enum
440{
441 WTS_SUCCESS,
442 WTS_NOT_READY,
443 WTS_FAILED_WITH_REPLY,
444 WTS_FAILED_WITHOUT_REPLY
445}
446test_wire_transfers (struct ANASTASIS_AUTHORIZATION_State *as)
447{
448 struct IBAN_Context *ctx = as->ctx;
449 struct ANASTASIS_DatabasePlugin *db = ctx->ac->db;
450 enum GNUNET_DB_QueryStatus qs;
451 struct GNUNET_TIME_Absolute now;
452 struct GNUNET_TIME_Absolute limit;
453 char *debit_account_uri;
454
455 now = GNUNET_TIME_absolute_get ();
456 limit = GNUNET_TIME_absolute_subtract (now,
457 CODE_VALIDITY_PERIOD);
458 GNUNET_asprintf (&debit_account_uri,
459 "payto://iban/%s",
460 as->iban_number);
461 qs = db->test_auth_iban_payment (
462 db->cls,
463 debit_account_uri,
464 limit,
465 &check_payment_ok,
466 as);
467 GNUNET_free (debit_account_uri);
468 switch (qs)
469 {
470 case GNUNET_DB_STATUS_HARD_ERROR:
471 case GNUNET_DB_STATUS_SOFT_ERROR:
472 return (MHD_YES ==
473 TALER_MHD_reply_with_error (as->connection,
474 MHD_HTTP_INTERNAL_SERVER_ERROR,
475 TALER_EC_GENERIC_DB_FETCH_FAILED,
476 NULL))
477 ? WTS_FAILED_WITH_REPLY
478 : WTS_FAILED_WITHOUT_REPLY;
479 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
480 return WTS_NOT_READY;
481 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
482 break;
483 }
484 qs = db->mark_challenge_code_satisfied (
485 db->cls,
486 &as->truth_uuid,
487 as->code);
488 GNUNET_break (qs > 0);
489 return WTS_SUCCESS;
371} 490}
372 491
373 492
@@ -423,6 +542,17 @@ iban_process (struct ANASTASIS_AUTHORIZATION_State *as,
423 return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED; 542 return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
424 return ANASTASIS_AUTHORIZATION_RES_FAILED; 543 return ANASTASIS_AUTHORIZATION_RES_FAILED;
425 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 544 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
545 switch (test_wire_transfers (as))
546 {
547 case WTS_SUCCESS:
548 return ANASTASIS_AUTHORIZATION_RES_FINISHED;
549 case WTS_NOT_READY:
550 break; /* continue below */
551 case WTS_FAILED_WITH_REPLY:
552 return ANASTASIS_AUTHORIZATION_RES_FAILED;
553 case WTS_FAILED_WITHOUT_REPLY:
554 return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
555 }
426 if (GNUNET_TIME_absolute_is_future (timeout)) 556 if (GNUNET_TIME_absolute_is_future (timeout))
427 { 557 {
428 as->connection = connection; 558 as->connection = connection;
@@ -529,9 +659,9 @@ libanastasis_plugin_authorization_iban_init (void *cls)
529 ctx->ac = ac; 659 ctx->ac = ac;
530 plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin); 660 plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin);
531 plugin->payment_plugin_managed = true; 661 plugin->payment_plugin_managed = true;
532 plugin->code_validity_period = GNUNET_TIME_UNIT_MONTHS; 662 plugin->code_validity_period = CODE_VALIDITY_PERIOD;
533 plugin->code_rotation_period = GNUNET_TIME_UNIT_WEEKS; 663 plugin->code_rotation_period = GNUNET_TIME_UNIT_WEEKS;
534 plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_FOREVER_REL; 664 plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_FOREVER_REL; /* not applicable */
535 plugin->cls = ctx; 665 plugin->cls = ctx;
536 plugin->validate = &iban_validate; 666 plugin->validate = &iban_validate;
537 plugin->start = &iban_start; 667 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 @@
1/**
2 * Extract a numeric @a code from a @a wire_subject.
3 * Also checks that the @a wire_subject contains the
4 * string "anastasis".
5 *
6 * @param wire_subject wire subject to extract @a code from
7 * @param[out] code where to write the extracted code
8 * @return #GNUNET_OK if a @a code was extracted
9 */
10static enum GNUNET_GenericReturnValue
11extract_code (const char *wire_subject,
12 uint64_t *code)
13{
14 unsigned long long c;
15 const char *pos;
16
17 if (0 !=
18 strcasestr (wire_subject,
19 "anastasis"))
20 {
21 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
22 "Keyword 'anastasis' missing in subject `%s', ignoring transfer\n",
23 wire_subject);
24 return GNUNET_SYSERR;
25 }
26 pos = wire_subject;
27 while ( ('\0' != *pos) &&
28 (! isdigit ((int) *pos)) )
29 pos++;
30 if (1 !=
31 sscanf (pos,
32 "%llu",
33 &c))
34 {
35 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
36 "Did not find any code number in subject `%s', ignoring transfer\n",
37 wire_subject);
38 return GNUNET_SYSERR;
39 }
40
41 *code = (uint64_t) c;
42 return GNUNET_OK;
43}
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
32struct IbanEventP 32struct IbanEventP
33{ 33{
34 /** 34 /**
35 * Header of type #TALER_DBEVENT_TYPE_ANASTASIS_AUTH_IBAN_TRANSFER. 35 * Header of type #TALER_DBEVENT_ANASTASIS_AUTH_IBAN_TRANSFER.
36 */ 36 */
37 struct GNUNET_DB_EventHeaderP header; 37 struct GNUNET_DB_EventHeaderP header;
38 38