summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/exchange/taler-exchange-httpd_withdraw.c20
-rw-r--r--src/exchangedb/exchange_do_withdraw.sql39
-rw-r--r--src/exchangedb/perf_deposits_get_ready.c5
-rw-r--r--src/exchangedb/pg_do_withdraw.c12
-rw-r--r--src/exchangedb/pg_do_withdraw.h6
-rw-r--r--src/include/taler_exchangedb_plugin.h6
-rw-r--r--src/kyclogic/plugin_kyclogic_oauth2.c3
-rw-r--r--src/lib/exchange_api_withdraw2.c11
-rw-r--r--src/testing/test_exchange_api_age_restriction-cs.conf2
-rw-r--r--src/testing/test_exchange_api_age_restriction.c2
10 files changed, 90 insertions, 16 deletions
diff --git a/src/exchange/taler-exchange-httpd_withdraw.c b/src/exchange/taler-exchange-httpd_withdraw.c
index cbc641410..07fcc8464 100644
--- a/src/exchange/taler-exchange-httpd_withdraw.c
+++ b/src/exchange/taler-exchange-httpd_withdraw.c
@@ -26,6 +26,7 @@
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
#include <jansson.h>
+#include "taler-exchange-httpd.h"
#include "taler_json_lib.h"
#include "taler_kyclogic_lib.h"
#include "taler_mhd_lib.h"
@@ -180,6 +181,8 @@ withdraw_transaction (void *cls,
bool found = false;
bool balance_ok = false;
bool nonce_ok = false;
+ bool age_ok = false;
+ uint16_t allowed_maximum_age = 0;
uint64_t ruuid;
const struct TALER_CsNonce *nonce;
const struct TALER_BlindedPlanchet *bp;
@@ -342,9 +345,12 @@ withdraw_transaction (void *cls,
nonce,
&wc->collectable,
wc->now,
+ TEH_age_restriction_enabled,
&found,
&balance_ok,
&nonce_ok,
+ &age_ok,
+ &allowed_maximum_age,
&ruuid);
if (0 > qs)
{
@@ -366,6 +372,20 @@ withdraw_transaction (void *cls,
NULL);
return GNUNET_DB_STATUS_HARD_ERROR;
}
+ if (! age_ok)
+ {
+ /* We respond with the lowest age in the corresponding age group
+ * of the required age */
+ uint16_t lowest_age = TALER_get_lowest_age (
+ &TEH_age_restriction_config.mask,
+ allowed_maximum_age);
+
+ TEH_plugin->rollback (TEH_plugin->cls);
+ *mhd_ret = TEH_RESPONSE_reply_reserve_age_restriction_required (
+ connection,
+ lowest_age);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
if (! balance_ok)
{
TEH_plugin->rollback (TEH_plugin->cls);
diff --git a/src/exchangedb/exchange_do_withdraw.sql b/src/exchangedb/exchange_do_withdraw.sql
index 9689bae5a..f6632c543 100644
--- a/src/exchangedb/exchange_do_withdraw.sql
+++ b/src/exchangedb/exchange_do_withdraw.sql
@@ -26,20 +26,22 @@ CREATE OR REPLACE FUNCTION exchange_do_withdraw(
IN denom_sig BYTEA,
IN now INT8,
IN min_reserve_gc INT8,
+ IN do_age_check BOOLEAN,
OUT reserve_found BOOLEAN,
OUT balance_ok BOOLEAN,
OUT nonce_ok BOOLEAN,
+ OUT age_ok BOOLEAN,
+ OUT allowed_maximum_age INT2, -- in years
OUT ruuid INT8)
LANGUAGE plpgsql
AS $$
DECLARE
reserve_gc INT8;
-DECLARE
denom_serial INT8;
-DECLARE
reserve_val INT8;
-DECLARE
reserve_frac INT4;
+ reserve_birthday INT4;
+ not_before date;
BEGIN
-- Shards: reserves by reserve_pub (SELECT)
-- reserves_out (INSERT, with CONFLICT detection) by wih
@@ -57,6 +59,8 @@ THEN
-- denomination unknown, should be impossible!
reserve_found=FALSE;
balance_ok=FALSE;
+ age_ok=FALSE;
+ allowed_maximum_age=0;
ruuid=0;
ASSERT false, 'denomination unknown';
RETURN;
@@ -67,11 +71,13 @@ SELECT
current_balance_val
,current_balance_frac
,gc_date
+ ,birthday
,reserve_uuid
INTO
reserve_val
,reserve_frac
,reserve_gc
+ ,reserve_birthday
,ruuid
FROM exchange.reserves
WHERE reserves.reserve_pub=rpub;
@@ -82,10 +88,33 @@ THEN
reserve_found=FALSE;
balance_ok=FALSE;
nonce_ok=TRUE;
+ age_ok=FALSE;
+ allowed_maximum_age=0;
ruuid=2;
RETURN;
END IF;
+-- Check if age requirements are present
+IF ((NOT do_age_check) OR (reserve_birthday = 0))
+THEN
+ age_ok = TRUE;
+ allowed_maximum_age = -1;
+ELSE
+ -- Age requirements are formally not met: The exchange is setup to support
+ -- age restrictions (do_age_check == TRUE) and the reserve has a
+ -- birthday set (reserve_birthday != 0), but the client called the
+ -- batch-withdraw endpoint instead of the age-withdraw endpoint, which it
+ -- should have.
+ not_before=date '1970-01-01' + reserve_birthday;
+ allowed_maximum_age = extract(year from age(current_date, not_before));
+
+ reserve_found=TRUE;
+ nonce_ok=TRUE; -- we do not really know
+ balance_ok=TRUE;-- we do not really know
+ age_ok = FALSE;
+ RETURN;
+END IF;
+
-- We optimistically insert, and then on conflict declare
-- the query successful due to idempotency.
INSERT INTO exchange.reserves_out
@@ -194,6 +223,6 @@ END IF;
END $$;
-COMMENT ON FUNCTION exchange_do_withdraw(BYTEA, INT8, INT4, BYTEA, BYTEA, BYTEA, BYTEA, BYTEA, INT8, INT8)
- IS 'Checks whether the reserve has sufficient balance for a withdraw operation (or the request is repeated and was previously approved) and if so updates the database with the result';
+COMMENT ON FUNCTION exchange_do_withdraw(BYTEA, INT8, INT4, BYTEA, BYTEA, BYTEA, BYTEA, BYTEA, INT8, INT8, BOOLEAN)
+ IS 'Checks whether the reserve has sufficient balance for a withdraw operation (or the request is repeated and was previously approved) and if the age requirements are formally met. If so updates the database with the result';
diff --git a/src/exchangedb/perf_deposits_get_ready.c b/src/exchangedb/perf_deposits_get_ready.c
index 4ad08223c..89699da24 100644
--- a/src/exchangedb/perf_deposits_get_ready.c
+++ b/src/exchangedb/perf_deposits_get_ready.c
@@ -363,6 +363,8 @@ run (void *cls)
bool found;
bool nonce_ok;
bool balance_ok;
+ bool age_ok;
+ uint16_t allowed_minimum_age;
uint64_t ruuid;
struct GNUNET_TIME_Timestamp now;
@@ -372,9 +374,12 @@ run (void *cls)
NULL,
&cbc,
now,
+ false,
&found,
&balance_ok,
&nonce_ok,
+ &age_ok,
+ &allowed_minimum_age,
&ruuid));
}
{
diff --git a/src/exchangedb/pg_do_withdraw.c b/src/exchangedb/pg_do_withdraw.c
index 01bbfff5b..99732df6b 100644
--- a/src/exchangedb/pg_do_withdraw.c
+++ b/src/exchangedb/pg_do_withdraw.c
@@ -32,9 +32,12 @@ TEH_PG_do_withdraw (
const struct TALER_CsNonce *nonce,
const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
struct GNUNET_TIME_Timestamp now,
+ bool do_age_check,
bool *found,
bool *balance_ok,
bool *nonce_ok,
+ bool *age_ok,
+ uint16_t *allowed_maximum_age,
uint64_t *ruuid)
{
struct PostgresClosure *pg = cls;
@@ -51,6 +54,7 @@ TEH_PG_do_withdraw (
TALER_PQ_query_param_blinded_denom_sig (&collectable->sig),
GNUNET_PQ_query_param_timestamp (&now),
GNUNET_PQ_query_param_timestamp (&gc),
+ GNUNET_PQ_query_param_bool (do_age_check),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
@@ -60,6 +64,10 @@ TEH_PG_do_withdraw (
balance_ok),
GNUNET_PQ_result_spec_bool ("nonce_ok",
nonce_ok),
+ GNUNET_PQ_result_spec_bool ("age_ok",
+ age_ok),
+ GNUNET_PQ_result_spec_uint16 ("allowed_maximum_age",
+ allowed_maximum_age),
GNUNET_PQ_result_spec_uint64 ("ruuid",
ruuid),
GNUNET_PQ_result_spec_end
@@ -71,9 +79,11 @@ TEH_PG_do_withdraw (
" reserve_found"
",balance_ok"
",nonce_ok"
+ ",age_ok"
+ ",allowed_maximum_age"
",ruuid"
" FROM exchange_do_withdraw"
- " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);");
+ " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11);");
gc = GNUNET_TIME_absolute_to_timestamp (
GNUNET_TIME_absolute_add (now.abs_time,
pg->legal_reserve_expiration_time));
diff --git a/src/exchangedb/pg_do_withdraw.h b/src/exchangedb/pg_do_withdraw.h
index 406785c42..e771b1ac7 100644
--- a/src/exchangedb/pg_do_withdraw.h
+++ b/src/exchangedb/pg_do_withdraw.h
@@ -33,9 +33,12 @@
* @param nonce client-contributed input for CS denominations that must be checked for idempotency, or NULL for non-CS withdrawals
* @param[in,out] collectable corresponding collectable coin (blind signature) if a coin is found; possibly updated if a (different) signature exists already
* @param now current time (rounded)
+ * @param do_age_check set to true if age requirements must be verified
* @param[out] found set to true if the reserve was found
* @param[out] balance_ok set to true if the balance was sufficient
* @param[out] nonce_ok set to false if the nonce was reused
+ * @param[out] age_ok set to true if age requirements are met
+ * @param[out] allowed_maximum_age if @e age_ok is false, the maximum age (in years) that is allowed during age-withdraw
* @param[out] ruuid set to the reserve's UUID (reserves table row)
* @return query execution status
*/
@@ -45,9 +48,12 @@ TEH_PG_do_withdraw (
const struct TALER_CsNonce *nonce,
const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
struct GNUNET_TIME_Timestamp now,
+ bool do_age_check,
bool *found,
bool *balance_ok,
bool *nonce_ok,
+ bool *age_ok,
+ uint16_t *allowed_maximum_age,
uint64_t *ruuid);
#endif
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index df051e867..c4b894e20 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -3745,9 +3745,12 @@ struct TALER_EXCHANGEDB_Plugin
* @param nonce client-contributed input for CS denominations that must be checked for idempotency, or NULL for non-CS withdrawals
* @param collectable corresponding collectable coin (blind signature)
* @param now current time (rounded)
+ * @param do_age_check set to true if age requirements must be checked.
* @param[out] found set to true if the reserve was found
* @param[out] balance_ok set to true if the balance was sufficient
* @param[out] nonce_ok set to false if the nonce was reused
+ * @param[out] age_ok set to true if no age requirements were defined on the reserve or @e do_age_check was false
+ * @param[out] allowed_maximum_age when @e age_ok is false, set to the allowed maximum age for withdrawal from the reserve. The client MUST then use the age-withdraw endpoint
* @param[out] ruuid set to the reserve's UUID (reserves table row)
* @return query execution status
*/
@@ -3757,9 +3760,12 @@ struct TALER_EXCHANGEDB_Plugin
const struct TALER_CsNonce *nonce,
const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
struct GNUNET_TIME_Timestamp now,
+ bool do_age_check,
bool *found,
bool *balance_ok,
bool *nonce_ok,
+ bool *age_ok,
+ uint16_t *allowed_maximum_age,
uint64_t *ruuid);
diff --git a/src/kyclogic/plugin_kyclogic_oauth2.c b/src/kyclogic/plugin_kyclogic_oauth2.c
index babbf4acd..c9e5d8dcf 100644
--- a/src/kyclogic/plugin_kyclogic_oauth2.c
+++ b/src/kyclogic/plugin_kyclogic_oauth2.c
@@ -922,9 +922,6 @@ data2attributes (const struct TALER_KYCLOGIC_ProviderDetails *pd,
JSON_INDENT (2));
return NULL;
}
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "XXXXXXXX plugin_kyc_logic SETTING ATTERIBUTES TO\n\t%s\n",
- json_dumps (data, JSON_INDENT (2)));
ret = json_loadb (attr_data,
attr_size,
JSON_REJECT_DUPLICATES,
diff --git a/src/lib/exchange_api_withdraw2.c b/src/lib/exchange_api_withdraw2.c
index bf9e2c091..6de7adccb 100644
--- a/src/lib/exchange_api_withdraw2.c
+++ b/src/lib/exchange_api_withdraw2.c
@@ -285,6 +285,12 @@ handle_reserve_withdraw_finished (void *cls,
w2r.hr.hint = TALER_JSON_get_error_hint (j);
break;
case MHD_HTTP_CONFLICT:
+ w2r.hr.ec = TALER_JSON_get_error_code (j);
+ w2r.hr.hint = TALER_JSON_get_error_hint (j);
+
+ if (TALER_EC_EXCHANGE_RESERVES_AGE_RESTRICTION_REQUIRED == w2r.hr.ec)
+ break;
+
/* The exchange says that the reserve has insufficient funds;
check the signatures in the history... */
if (GNUNET_OK !=
@@ -295,11 +301,6 @@ handle_reserve_withdraw_finished (void *cls,
w2r.hr.http_status = 0;
w2r.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
}
- else
- {
- w2r.hr.ec = TALER_JSON_get_error_code (j);
- w2r.hr.hint = TALER_JSON_get_error_hint (j);
- }
break;
case MHD_HTTP_GONE:
/* could happen if denomination was revoked */
diff --git a/src/testing/test_exchange_api_age_restriction-cs.conf b/src/testing/test_exchange_api_age_restriction-cs.conf
index b80696fb2..12195f9ba 100644
--- a/src/testing/test_exchange_api_age_restriction-cs.conf
+++ b/src/testing/test_exchange_api_age_restriction-cs.conf
@@ -1,4 +1,4 @@
# This file is in the public domain.
#
+@INLINE@ test_exchange_api_age_restriction.conf
@INLINE@ coins-cs.conf
-@INLINE@ test_exchange_api.conf
diff --git a/src/testing/test_exchange_api_age_restriction.c b/src/testing/test_exchange_api_age_restriction.c
index 0aaa7bbf9..93bd28bf9 100644
--- a/src/testing/test_exchange_api_age_restriction.c
+++ b/src/testing/test_exchange_api_age_restriction.c
@@ -302,7 +302,7 @@ run (void *cls,
true,
true),
TALER_TESTING_cmd_oauth_with_birthdate ("oauth-service-with-birthdate",
- "2022-00-00", /* enough for a while */
+ "2015-00-00", /* enough for a while */
6666),
TALER_TESTING_cmd_batch ("withdraw-age",
withdraw_age),