diff options
author | Christian Grothoff <christian@grothoff.org> | 2021-08-19 13:41:30 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2021-08-19 13:41:30 +0200 |
commit | 81d0e570be0db784e98fdb7ad63f9b65c6745be3 (patch) | |
tree | 578a91bd888abfac827c23ba2933174c7d2341de | |
parent | 87bc2f469bf120bbd57e98a0a8ea46e80de84927 (diff) | |
download | anastasis-81d0e570be0db784e98fdb7ad63f9b65c6745be3.tar.gz anastasis-81d0e570be0db784e98fdb7ad63f9b65c6745be3.zip |
-implement DB triggers and check for inbound wire transfers in IBAN plugin
-rw-r--r-- | src/authorization/Makefile.am | 3 | ||||
-rw-r--r-- | src/authorization/anastasis-helper-authorization-iban.c | 50 | ||||
-rw-r--r-- | src/authorization/anastasis_authorization_plugin_iban.c | 134 | ||||
-rw-r--r-- | src/authorization/iban.c | 43 | ||||
-rw-r--r-- | src/authorization/iban.h | 2 |
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 | ||
16 | EXTRA_DIST = \ | 16 | EXTRA_DIST = \ |
17 | $(pkgdata_DATA) \ | 17 | $(pkgdata_DATA) \ |
18 | iban.h | 18 | iban.h iban.c |
19 | 19 | ||
20 | 20 | ||
21 | if USE_COVERAGE | 21 | if 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 | */ | ||
115 | static void | ||
116 | notify (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 | |||
152 | find_transfers (void *cls); | 180 | find_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 | */ |
34 | struct IBAN_Context | 44 | struct 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 | */ | ||
395 | static bool | ||
396 | check_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 | */ | ||
439 | static enum | ||
440 | { | ||
441 | WTS_SUCCESS, | ||
442 | WTS_NOT_READY, | ||
443 | WTS_FAILED_WITH_REPLY, | ||
444 | WTS_FAILED_WITHOUT_REPLY | ||
445 | } | ||
446 | test_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 | */ | ||
10 | static enum GNUNET_GenericReturnValue | ||
11 | extract_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 | |||
32 | struct IbanEventP | 32 | struct 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 | ||