summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÖzgür Kesim <oec-taler@kesim.org>2023-06-27 09:45:50 +0200
committerÖzgür Kesim <oec-taler@kesim.org>2023-06-27 09:45:50 +0200
commit145310e20e1a80d7c3a4a76a27f1e415bea7b3ce (patch)
tree0ab96ce9160504ce2df2171f3a4cb9a2de068339
parentddd0e0af136f694db6013abd0344f20c1931bad9 (diff)
downloadexchange-145310e20e1a80d7c3a4a76a27f1e415bea7b3ce.tar.gz
exchange-145310e20e1a80d7c3a4a76a27f1e415bea7b3ce.tar.bz2
exchange-145310e20e1a80d7c3a4a76a27f1e415bea7b3ce.zip
added birthdate parser
-rw-r--r--src/exchange/taler-exchange-httpd_common_kyc.c33
-rw-r--r--src/include/taler_util.h28
-rw-r--r--src/util/age_restriction.c53
-rw-r--r--src/util/test_age_restriction.c73
4 files changed, 183 insertions, 4 deletions
diff --git a/src/exchange/taler-exchange-httpd_common_kyc.c b/src/exchange/taler-exchange-httpd_common_kyc.c
index b6585ed58..bb3ca4795 100644
--- a/src/exchange/taler-exchange-httpd_common_kyc.c
+++ b/src/exchange/taler-exchange-httpd_common_kyc.c
@@ -19,9 +19,12 @@
* @author Christian Grothoff
*/
#include "platform.h"
+#include "taler-exchange-httpd.h"
#include "taler-exchange-httpd_common_kyc.h"
#include "taler_attributes.h"
+#include "taler_error_codes.h"
#include "taler_exchangedb_plugin.h"
+#include <gnunet/gnunet_common.h>
struct TEH_KycAmlTrigger
{
@@ -114,7 +117,7 @@ kyc_aml_finished (void *cls,
size_t eas;
void *ea;
const char *birthdate;
- unsigned int birthday;
+ unsigned int birthday = 0;
struct GNUNET_ShortHashCode kyc_prox;
struct GNUNET_AsyncScopeSave old_scope;
@@ -125,9 +128,29 @@ kyc_aml_finished (void *cls,
&kyc_prox);
birthdate = json_string_value (json_object_get (kat->attributes,
TALER_ATTRIBUTE_BIRTHDATE));
- birthday = 0; (void) birthdate; // FIXME-Oec: calculate birthday here...
- // Convert 'birthdate' to time after 1970, then compute days.
- // Then compare against max age-restriction, and if before, set to 0.
+
+ if (TEH_age_restriction_enabled)
+ {
+ enum GNUNET_GenericReturnValue ret;
+
+ ret = TALER_parse_coarse_date (birthdate,
+ &TEH_age_restriction_config.mask,
+ &birthday);
+
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_break (0);
+ if (NULL != kat->response)
+ MHD_destroy_response (kat->response);
+ kat->http_status = MHD_HTTP_BAD_REQUEST;
+ kat->response = TALER_MHD_make_error (
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ TALER_ATTRIBUTE_BIRTHDATE);
+
+ /* FIXME-Christian: shouldn't we return in the error case? */
+ }
+ }
+
TALER_CRYPTO_kyc_attributes_encrypt (&TEH_attribute_key,
kat->attributes,
&ea,
@@ -159,6 +182,8 @@ kyc_aml_finished (void *cls,
kat->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
kat->response = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
"do_insert_kyc_attributes");
+
+ /* FIXME-Christian: shouldn't we return in the error case? */
}
/* Finally, return result to main handler */
kat->cb (kat->cb_cls,
diff --git a/src/include/taler_util.h b/src/include/taler_util.h
index 1f3a4c706..dc30fca31 100644
--- a/src/include/taler_util.h
+++ b/src/include/taler_util.h
@@ -21,6 +21,7 @@
#ifndef TALER_UTIL_H
#define TALER_UTIL_H
+#include <gnunet/gnunet_common.h>
#define __TALER_UTIL_LIB_H_INSIDE__
#include <gnunet/gnunet_util_lib.h>
@@ -511,6 +512,33 @@ char *strchrnul (const char *s, int c);
#endif
/**
+ * @brief Parses a date information into days after 1970-01-01 (or 0)
+ *
+ * The input MUST be of the form
+ *
+ * 1) YYYY-MM-DD, representing a valid date
+ * 2) YYYY-MM-00, representing a valid month in a particular year
+ * 3) YYYY-00-00, representing a valid year.
+ *
+ * In the cases 2) and 3) the out parameter is set to the beginning of the
+ * time, f.e. 1950-00-00 == 1950-01-01 and 1888-03-00 == 1888-03-01
+ *
+ * The output will set to the number of days after 1970-01-01 or 0, if the input
+ * represents a date belonging to the largest allowed age group.
+ *
+ * @param in Input string representation of the date
+ * @param mask Age mask
+ * @param[out] out Where to write the result
+ * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
+ */
+enum GNUNET_GenericReturnValue
+TALER_parse_coarse_date (
+ const char *in,
+ const struct TALER_AgeMask *mask,
+ uint32_t *out);
+
+
+/**
* @brief Parses a string as a list of age groups.
*
* The string must consist of a colon-separated list of increasing integers
diff --git a/src/util/age_restriction.c b/src/util/age_restriction.c
index b667fa3a9..839ed7cd5 100644
--- a/src/util/age_restriction.c
+++ b/src/util/age_restriction.c
@@ -710,4 +710,57 @@ TALER_age_restriction_from_secret (
}
+enum GNUNET_GenericReturnValue
+TALER_parse_coarse_date (
+ const char *in,
+ const struct TALER_AgeMask *mask,
+ uint32_t *out)
+{
+ struct tm date = {0};
+ struct tm limit = {0};
+ time_t seconds;
+
+ if (NULL == in)
+ {
+ /* FIXME[oec]: correct behaviour? */
+ *out = 0;
+ return GNUNET_OK;
+ }
+
+ GNUNET_assert (NULL !=mask);
+ GNUNET_assert (NULL !=out);
+
+ if (NULL == strptime (in, "%Y-%0m-%0d", &date))
+ {
+ if (NULL == strptime (in, "%Y-%0m-00", &date))
+ if (NULL == strptime (in, "%Y-00-00", &date))
+ return GNUNET_SYSERR;
+
+ /* turns out that the day is off by one in the last two cases */
+ date.tm_mday += 1;
+ }
+
+ seconds = mktime (&date);
+ if (-1 == seconds)
+ return GNUNET_SYSERR;
+
+ /* calculate the limit date for the largest age group */
+ localtime_r (&(time_t){time (NULL)}, &limit);
+ limit.tm_year -= TALER_get_lowest_age (mask, 255);
+ GNUNET_assert (-1 != mktime (&limit));
+
+ if ((limit.tm_year < date.tm_year)
+ || ((limit.tm_year == date.tm_year)
+ && (limit.tm_mon < date.tm_mon))
+ || ((limit.tm_year == date.tm_year)
+ && (limit.tm_mon == date.tm_mon)
+ && (limit.tm_mday < date.tm_mday)))
+ *out = seconds / 60 / 60 / 24;
+ else
+ *out = 0;
+
+ return GNUNET_OK;
+}
+
+
/* end util/age_restriction.c */
diff --git a/src/util/test_age_restriction.c b/src/util/test_age_restriction.c
index e1979314e..29e722acc 100644
--- a/src/util/test_age_restriction.c
+++ b/src/util/test_age_restriction.c
@@ -130,6 +130,77 @@ test_groups (void)
enum GNUNET_GenericReturnValue
+test_dates (void)
+{
+ struct TALER_AgeMask mask = {
+ .bits = 1 | 1 << 5 | 1 << 9 | 1 << 13 | 1 << 17 | 1 << 21
+ };
+
+ struct
+ {
+ char *date;
+ uint32_t expected;
+ enum GNUNET_GenericReturnValue ret;
+ }
+ test [] = {
+ {.date = "abcd-00-00", .expected = 0, .ret = GNUNET_SYSERR},
+ {.date = "1900-00-01", .expected = 0, .ret = GNUNET_SYSERR},
+ {.date = "19000001", .expected = 0, .ret = GNUNET_SYSERR},
+ {.date = "2001-33-05", .expected = 0, .ret = GNUNET_SYSERR},
+ {.date = "2001-33-35", .expected = 0, .ret = GNUNET_SYSERR},
+
+ {.date = "1900-00-00", .expected = 0, .ret = GNUNET_OK},
+ {.date = "2001-00-00", .expected = 0, .ret = GNUNET_OK},
+ {.date = "2001-03-00", .expected = 0, .ret = GNUNET_OK},
+ {.date = "2001-03-05", .expected = 0, .ret = GNUNET_OK},
+
+ /* These dates should be far enough for the near future so that
+ * the expected values are correct. Will need adjustment in 2044 :) */
+ {.date = "2023-06-26", .expected = 19533, .ret = GNUNET_OK },
+ {.date = "2023-06-01", .expected = 19508, .ret = GNUNET_OK },
+ {.date = "2023-06-00", .expected = 19508, .ret = GNUNET_OK },
+ {.date = "2023-01-01", .expected = 19357, .ret = GNUNET_OK },
+ {.date = "2023-00-00", .expected = 19357, .ret = GNUNET_OK },
+ };
+
+ for (uint8_t t = 0; t < sizeof(test) / sizeof(test[0]); t++)
+ {
+ uint32_t d;
+ enum GNUNET_GenericReturnValue ret;
+
+ ret = TALER_parse_coarse_date (test[t].date,
+ &mask,
+ &d);
+ if (ret != test[t].ret)
+ {
+ printf (
+ "dates[%d] for date `%s` expected parser to return: %d, got: %d\n",
+ t, test[t].date, test[t].ret, ret);
+ return GNUNET_SYSERR;
+ }
+
+ if (ret == GNUNET_SYSERR)
+ continue;
+
+ if (d != test[t].expected)
+ {
+ printf (
+ "dates[%d] for date `%s` expected value %d, but got %d\n",
+ t, test[t].date, test[t].expected, d);
+ return GNUNET_SYSERR;
+ }
+
+ printf ("dates[%d] for date `%s` got expected value %d\n",
+ t, test[t].date, d);
+ }
+
+ printf ("done with dates\n");
+
+ return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
test_lowest (void)
{
struct TALER_AgeMask mask = {
@@ -308,6 +379,8 @@ main (int argc,
GNUNET_break (0);
return 3;
}
+ if (GNUNET_OK != test_dates ())
+ return 4;
return 0;
}