From 75f75c4a51c4700da9bde18cc9a9b5d9df1e8457 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 30 Apr 2023 16:21:07 +0200 Subject: breaking protocol changes towards fixing #7810 (incomplete, taler-exchange-offline still unfinished) --- src/util/offline_signatures.c | 78 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) (limited to 'src/util') diff --git a/src/util/offline_signatures.c b/src/util/offline_signatures.c index b1e3b93a..15dda8b3 100644 --- a/src/util/offline_signatures.c +++ b/src/util/offline_signatures.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2020-2022 Taler Systems SA + Copyright (C) 2020-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -677,6 +677,22 @@ struct TALER_MasterAddWirePS * Hash over the exchange's payto URI. */ struct TALER_PaytoHashP h_payto GNUNET_PACKED; + + /** + * Hash over the conversion URL, all zeros if there + * is no conversion URL. + */ + struct GNUNET_HashCode h_conversion_url; + + /** + * Hash over the debit restrictions. + */ + struct GNUNET_HashCode h_debit_restrictions; + + /** + * Hash over the credit restrictions. + */ + struct GNUNET_HashCode h_credit_restrictions; }; GNUNET_NETWORK_STRUCT_END @@ -685,6 +701,9 @@ GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_wire_add_sign ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, struct GNUNET_TIME_Timestamp now, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) @@ -697,6 +716,14 @@ TALER_exchange_offline_wire_add_sign ( TALER_payto_hash (payto_uri, &kv.h_payto); + if (NULL != conversion_url) + GNUNET_CRYPTO_hash (conversion_url, + strlen (conversion_url), + &kv.h_conversion_url); + TALER_json_hash (debit_restrictions, + &kv.h_debit_restrictions); + TALER_json_hash (credit_restrictions, + &kv.h_credit_restrictions); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &kv, &master_sig->eddsa_signature); @@ -706,6 +733,9 @@ TALER_exchange_offline_wire_add_sign ( enum GNUNET_GenericReturnValue TALER_exchange_offline_wire_add_verify ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, struct GNUNET_TIME_Timestamp sign_time, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) @@ -718,6 +748,14 @@ TALER_exchange_offline_wire_add_verify ( TALER_payto_hash (payto_uri, &aw.h_payto); + if (NULL != conversion_url) + GNUNET_CRYPTO_hash (conversion_url, + strlen (conversion_url), + &aw.h_conversion_url); + TALER_json_hash (debit_restrictions, + &aw.h_debit_restrictions); + TALER_json_hash (credit_restrictions, + &aw.h_credit_restrictions); return GNUNET_CRYPTO_eddsa_verify ( TALER_SIGNATURE_MASTER_ADD_WIRE, @@ -1095,6 +1133,22 @@ struct TALER_MasterWireDetailsPS */ struct TALER_PaytoHashP h_wire_details GNUNET_PACKED; + /** + * Hash over the conversion URL, all zeros if there + * is no conversion URL. + */ + struct GNUNET_HashCode h_conversion_url; + + /** + * Hash over the debit restrictions. + */ + struct GNUNET_HashCode h_debit_restrictions; + + /** + * Hash over the credit restrictions. + */ + struct GNUNET_HashCode h_credit_restrictions; + }; GNUNET_NETWORK_STRUCT_END @@ -1103,6 +1157,9 @@ GNUNET_NETWORK_STRUCT_END enum GNUNET_GenericReturnValue TALER_exchange_wire_signature_check ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { @@ -1113,6 +1170,14 @@ TALER_exchange_wire_signature_check ( TALER_payto_hash (payto_uri, &wd.h_wire_details); + if (NULL != conversion_url) + GNUNET_CRYPTO_hash (conversion_url, + strlen (conversion_url), + &wd.h_conversion_url); + TALER_json_hash (debit_restrictions, + &wd.h_debit_restrictions); + TALER_json_hash (credit_restrictions, + &wd.h_credit_restrictions); return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_WIRE_DETAILS, &wd, &master_sig->eddsa_signature, @@ -1123,6 +1188,9 @@ TALER_exchange_wire_signature_check ( void TALER_exchange_wire_signature_make ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { @@ -1133,6 +1201,14 @@ TALER_exchange_wire_signature_make ( TALER_payto_hash (payto_uri, &wd.h_wire_details); + if (NULL != conversion_url) + GNUNET_CRYPTO_hash (conversion_url, + strlen (conversion_url), + &wd.h_conversion_url); + TALER_json_hash (debit_restrictions, + &wd.h_debit_restrictions); + TALER_json_hash (credit_restrictions, + &wd.h_credit_restrictions); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &wd, &master_sig->eddsa_signature); -- cgit v1.2.3 From ffd4057c61a1c507e348b76d1df10641c7ed64b1 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 2 May 2023 17:29:41 +0200 Subject: use same canonicalization of JSON as for contract hashes when doing normal JSON hashing --- src/json/json.c | 168 +------------------------------------------------------ src/util/util.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 169 insertions(+), 168 deletions(-) (limited to 'src/util') diff --git a/src/json/json.c b/src/json/json.c index 7d7e4ecb..832863f3 100644 --- a/src/json/json.c +++ b/src/json/json.c @@ -61,170 +61,6 @@ contains_real (const json_t *json) } -/** - * Dump character in the low range into @a buf - * following RFC 8785. - * - * @param[in,out] buf buffer to modify - * @param val value to dump - */ -static void -lowdump (struct GNUNET_Buffer *buf, - unsigned char val) -{ - char scratch[7]; - - switch (val) - { - case 0x8: - GNUNET_buffer_write (buf, - "\\b", - 2); - break; - case 0x9: - GNUNET_buffer_write (buf, - "\\t", - 2); - break; - case 0xA: - GNUNET_buffer_write (buf, - "\\n", - 2); - break; - case 0xC: - GNUNET_buffer_write (buf, - "\\f", - 2); - break; - case 0xD: - GNUNET_buffer_write (buf, - "\\r", - 2); - break; - default: - GNUNET_snprintf (scratch, - sizeof (scratch), - "\\u%04x", - (unsigned int) val); - GNUNET_buffer_write (buf, - scratch, - 6); - break; - } -} - - -/** - * Re-encode string at @a inp to match RFC 8785 (section 3.2.2.2). - * - * @param[in,out] inp pointer to string to re-encode - * @return number of bytes in resulting @a inp - */ -static size_t -rfc8785encode (char **inp) -{ - struct GNUNET_Buffer buf = { 0 }; - size_t left = strlen (*inp) + 1; - size_t olen; - char *in = *inp; - const char *pos = in; - - GNUNET_buffer_prealloc (&buf, - left + 40); - buf.warn_grow = 0; /* disable, + 40 is just a wild guess */ - while (1) - { - int mbl = u8_mblen ((unsigned char *) pos, - left); - unsigned char val; - - if (0 == mbl) - break; - val = (unsigned char) *pos; - if ( (1 == mbl) && - (val <= 0x1F) ) - { - /* Should not happen, as input is produced by - * JSON stringification */ - GNUNET_break (0); - lowdump (&buf, - val); - } - else if ( (1 == mbl) && ('\\' == *pos) ) - { - switch (*(pos + 1)) - { - case '\\': - mbl = 2; - GNUNET_buffer_write (&buf, - pos, - mbl); - break; - case 'u': - { - unsigned int num; - uint32_t n32; - unsigned char res[8]; - size_t rlen; - - GNUNET_assert ( (1 == - sscanf (pos + 2, - "%4x", - &num)) || - (1 == - sscanf (pos + 2, - "%4X", - &num)) ); - mbl = 6; - n32 = (uint32_t) num; - rlen = sizeof (res); - u32_to_u8 (&n32, - 1, - res, - &rlen); - if ( (1 == rlen) && - (res[0] <= 0x1F) ) - { - lowdump (&buf, - res[0]); - } - else - { - GNUNET_buffer_write (&buf, - (const char *) res, - rlen); - } - } - break; - default: - mbl = 2; - GNUNET_buffer_write (&buf, - pos, - mbl); - break; - } - } - else - { - GNUNET_buffer_write (&buf, - pos, - mbl); - } - left -= mbl; - pos += mbl; - } - - /* 0-terminate buffer */ - GNUNET_buffer_write (&buf, - "", - 1); - GNUNET_free (in); - *inp = GNUNET_buffer_reap (&buf, - &olen); - return olen; -} - - /** * Dump the @a json to a string and hash it. * @@ -262,7 +98,7 @@ dump_and_hash (const json_t *json, GNUNET_break (0); return GNUNET_SYSERR; } - len = rfc8785encode (&wire_enc); + len = TALER_rfc8785encode (&wire_enc); if (NULL == salt) { GNUNET_CRYPTO_hash (wire_enc, @@ -1031,7 +867,7 @@ TALER_JSON_canonicalize (const json_t *input) GNUNET_break (0); return NULL; } - rfc8785encode (&wire_enc); + TALER_rfc8785encode (&wire_enc); return wire_enc; } diff --git a/src/util/util.c b/src/util/util.c index 96d79191..7cd4b0c3 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -25,6 +25,7 @@ #include "taler_util.h" #include "taler_attributes.h" #include +#include const char * @@ -204,6 +205,170 @@ TALER_denom_fee_check_currency ( } +/** + * Dump character in the low range into @a buf + * following RFC 8785. + * + * @param[in,out] buf buffer to modify + * @param val value to dump + */ +static void +lowdump (struct GNUNET_Buffer *buf, + unsigned char val) +{ + char scratch[7]; + + switch (val) + { + case 0x8: + GNUNET_buffer_write (buf, + "\\b", + 2); + break; + case 0x9: + GNUNET_buffer_write (buf, + "\\t", + 2); + break; + case 0xA: + GNUNET_buffer_write (buf, + "\\n", + 2); + break; + case 0xC: + GNUNET_buffer_write (buf, + "\\f", + 2); + break; + case 0xD: + GNUNET_buffer_write (buf, + "\\r", + 2); + break; + default: + GNUNET_snprintf (scratch, + sizeof (scratch), + "\\u%04x", + (unsigned int) val); + GNUNET_buffer_write (buf, + scratch, + 6); + break; + } +} + + +/** + * Re-encode string at @a inp to match RFC 8785 (section 3.2.2.2). + * + * @param[in,out] inp pointer to string to re-encode + * @return number of bytes in resulting @a inp + */ +size_t +TALER_rfc8785encode (char **inp) +{ + struct GNUNET_Buffer buf = { 0 }; + size_t left = strlen (*inp) + 1; + size_t olen; + char *in = *inp; + const char *pos = in; + + GNUNET_buffer_prealloc (&buf, + left + 40); + buf.warn_grow = 0; /* disable, + 40 is just a wild guess */ + while (1) + { + int mbl = u8_mblen ((unsigned char *) pos, + left); + unsigned char val; + + if (0 == mbl) + break; + val = (unsigned char) *pos; + if ( (1 == mbl) && + (val <= 0x1F) ) + { + /* Should not happen, as input is produced by + * JSON stringification */ + GNUNET_break (0); + lowdump (&buf, + val); + } + else if ( (1 == mbl) && ('\\' == *pos) ) + { + switch (*(pos + 1)) + { + case '\\': + mbl = 2; + GNUNET_buffer_write (&buf, + pos, + mbl); + break; + case 'u': + { + unsigned int num; + uint32_t n32; + unsigned char res[8]; + size_t rlen; + + GNUNET_assert ( (1 == + sscanf (pos + 2, + "%4x", + &num)) || + (1 == + sscanf (pos + 2, + "%4X", + &num)) ); + mbl = 6; + n32 = (uint32_t) num; + rlen = sizeof (res); + u32_to_u8 (&n32, + 1, + res, + &rlen); + if ( (1 == rlen) && + (res[0] <= 0x1F) ) + { + lowdump (&buf, + res[0]); + } + else + { + GNUNET_buffer_write (&buf, + (const char *) res, + rlen); + } + } + break; + default: + mbl = 2; + GNUNET_buffer_write (&buf, + pos, + mbl); + break; + } + } + else + { + GNUNET_buffer_write (&buf, + pos, + mbl); + } + left -= mbl; + pos += mbl; + } + + /* 0-terminate buffer */ + GNUNET_buffer_write (&buf, + "", + 1); + GNUNET_free (in); + *inp = GNUNET_buffer_reap (&buf, + &olen); + return olen; +} + + /** * Hash normalized @a j JSON object or array and * store the result in @a hc. @@ -221,11 +386,11 @@ TALER_json_hash (const json_t *j, cstr = json_dumps (j, JSON_COMPACT | JSON_SORT_KEYS); GNUNET_assert (NULL != cstr); - clen = strlen (cstr); + clen = TALER_rfc8785encode (&cstr); GNUNET_CRYPTO_hash (cstr, clen, hc); - free (cstr); + GNUNET_free (cstr); } -- cgit v1.2.3 From 4267f1d76299252de273fa723c6037fef30fb7f1 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 2 May 2023 17:32:26 +0200 Subject: include 0-terminator when hashing --- src/util/offline_signatures.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/util') diff --git a/src/util/offline_signatures.c b/src/util/offline_signatures.c index 15dda8b3..40ccfbc2 100644 --- a/src/util/offline_signatures.c +++ b/src/util/offline_signatures.c @@ -718,7 +718,7 @@ TALER_exchange_offline_wire_add_sign ( &kv.h_payto); if (NULL != conversion_url) GNUNET_CRYPTO_hash (conversion_url, - strlen (conversion_url), + strlen (conversion_url) + 1, &kv.h_conversion_url); TALER_json_hash (debit_restrictions, &kv.h_debit_restrictions); @@ -750,7 +750,7 @@ TALER_exchange_offline_wire_add_verify ( &aw.h_payto); if (NULL != conversion_url) GNUNET_CRYPTO_hash (conversion_url, - strlen (conversion_url), + strlen (conversion_url) + 1, &aw.h_conversion_url); TALER_json_hash (debit_restrictions, &aw.h_debit_restrictions); @@ -1172,7 +1172,7 @@ TALER_exchange_wire_signature_check ( &wd.h_wire_details); if (NULL != conversion_url) GNUNET_CRYPTO_hash (conversion_url, - strlen (conversion_url), + strlen (conversion_url) + 1, &wd.h_conversion_url); TALER_json_hash (debit_restrictions, &wd.h_debit_restrictions); @@ -1203,7 +1203,7 @@ TALER_exchange_wire_signature_make ( &wd.h_wire_details); if (NULL != conversion_url) GNUNET_CRYPTO_hash (conversion_url, - strlen (conversion_url), + strlen (conversion_url) + 1, &wd.h_conversion_url); TALER_json_hash (debit_restrictions, &wd.h_debit_restrictions); -- cgit v1.2.3 From 2de2b6e3cfbd6e766d02b3c44e2238aafaa91baa Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 4 May 2023 16:04:29 +0200 Subject: -fix crypto test --- src/util/test_crypto.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'src/util') diff --git a/src/util/test_crypto.c b/src/util/test_crypto.c index 80a24777..80ce9083 100644 --- a/src/util/test_crypto.c +++ b/src/util/test_crypto.c @@ -355,15 +355,24 @@ test_exchange_sigs (void) struct TALER_MasterPrivateKeyP priv; struct TALER_MasterPublicKeyP pub; struct TALER_MasterSignatureP sig; + json_t *rest; GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv); + rest = json_array (); + GNUNET_assert (NULL != rest); TALER_exchange_wire_signature_make (pt, + NULL, + rest, + rest, &priv, &sig); GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv, &pub.eddsa_pub); if (GNUNET_OK != TALER_exchange_wire_signature_check (pt, + NULL, + rest, + rest, &pub, &sig)) { @@ -373,12 +382,28 @@ test_exchange_sigs (void) if (GNUNET_OK == TALER_exchange_wire_signature_check ( "payto://x-taler-bank/localhost/Other", + NULL, + rest, + rest, &pub, &sig)) { GNUNET_break (0); return 1; } + if (GNUNET_OK == + TALER_exchange_wire_signature_check ( + pt, + "http://example.com/", + rest, + rest, + &pub, + &sig)) + { + GNUNET_break (0); + return 1; + } + json_decref (rest); return 0; } -- cgit v1.2.3 From dc5b0fb0d35b9758f6eac7b0bd144db00eef7216 Mon Sep 17 00:00:00 2001 From: Özgür Kesim Date: Tue, 9 May 2023 20:40:43 +0200 Subject: Fix age mask parsing from config - initialize age mask to zero - drop default bitstring for age mask, use string instead -remove default age mask bits, use string instead -strdup --- src/extensions/age_restriction/age_restriction.c | 6 +++--- src/include/taler_extensions.h | 4 ---- src/util/age_restriction.c | 3 +++ 3 files changed, 6 insertions(+), 7 deletions(-) (limited to 'src/util') diff --git a/src/extensions/age_restriction/age_restriction.c b/src/extensions/age_restriction/age_restriction.c index 2d6d0cbd..481cb133 100644 --- a/src/extensions/age_restriction/age_restriction.c +++ b/src/extensions/age_restriction/age_restriction.c @@ -207,10 +207,10 @@ libtaler_extension_age_restriction_init (void *arg) return NULL; } - mask.bits = TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK; + if (NULL == groups) + groups = GNUNET_strdup (TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_GROUPS); - if ((groups != NULL) && - (GNUNET_OK != TALER_parse_age_group_string (groups, &mask))) + if (GNUNET_OK != TALER_parse_age_group_string (groups, &mask)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[age restriction] couldn't parse age groups: '%s'\n", diff --git a/src/include/taler_extensions.h b/src/include/taler_extensions.h index bd5b7248..75f22534 100644 --- a/src/include/taler_extensions.h +++ b/src/include/taler_extensions.h @@ -344,10 +344,6 @@ TALER_extensions_verify_manifests_signature ( * The default age mask represents the age groups * 0-7, 8-9, 10-11, 12-13, 14-15, 16-17, 18-20, 21-... */ -#define TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK (1 | 1 << 8 | 1 << 10 \ - | 1 << 12 | 1 << 14 \ - | 1 << 16 | 1 << 18 \ - | 1 << 21) #define TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_GROUPS "8:10:12:14:16:18:21" diff --git a/src/util/age_restriction.c b/src/util/age_restriction.c index beb68e5a..cf81d915 100644 --- a/src/util/age_restriction.c +++ b/src/util/age_restriction.c @@ -513,6 +513,9 @@ TALER_parse_age_group_string ( unsigned int val = 0; char c; + /* reset mask */ + mask->bits = 0; + while (*pos) { c = *pos++; -- cgit v1.2.3 From 4e79967f9ba980b64e89a453efbb9ed4bfa4cc37 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 9 May 2023 23:52:57 +0200 Subject: -consistency --- src/util/offline_signatures.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/util') diff --git a/src/util/offline_signatures.c b/src/util/offline_signatures.c index 40ccfbc2..fbff850d 100644 --- a/src/util/offline_signatures.c +++ b/src/util/offline_signatures.c @@ -1005,9 +1005,9 @@ TALER_exchange_offline_global_fee_sign ( const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { - struct TALER_MasterGlobalFeePS kv = { + struct TALER_MasterGlobalFeePS wf = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_GLOBAL_FEES), - .purpose.size = htonl (sizeof (kv)), + .purpose.size = htonl (sizeof (wf)), .start_date = GNUNET_TIME_timestamp_hton (start_time), .end_date = GNUNET_TIME_timestamp_hton (end_time), .purse_timeout = GNUNET_TIME_relative_hton (purse_timeout), @@ -1015,10 +1015,10 @@ TALER_exchange_offline_global_fee_sign ( .purse_account_limit = htonl (purse_account_limit) }; - TALER_global_fee_set_hton (&kv.fees, + TALER_global_fee_set_hton (&wf.fees, fees); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, - &kv, + &wf, &master_sig->eddsa_signature); } -- cgit v1.2.3 From 1cf58e8ff8efc82f0e8bf1a058047d48b86e060e Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 10 May 2023 00:02:52 +0200 Subject: -fix warning --- src/include/taler_util.h | 10 ++++++++++ src/util/util.c | 6 ------ 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src/util') diff --git a/src/include/taler_util.h b/src/include/taler_util.h index 8192ed87..6c294822 100644 --- a/src/include/taler_util.h +++ b/src/include/taler_util.h @@ -229,6 +229,16 @@ void TALER_OS_init (void); +/** + * Re-encode string at @a inp to match RFC 8785 (section 3.2.2.2). + * + * @param[in,out] inp pointer to string to re-encode + * @return number of bytes in resulting @a inp + */ +size_t +TALER_rfc8785encode (char **inp); + + /** * URL-encode a string according to rfc3986. * diff --git a/src/util/util.c b/src/util/util.c index 7cd4b0c3..82c5f7f3 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -258,12 +258,6 @@ lowdump (struct GNUNET_Buffer *buf, } -/** - * Re-encode string at @a inp to match RFC 8785 (section 3.2.2.2). - * - * @param[in,out] inp pointer to string to re-encode - * @return number of bytes in resulting @a inp - */ size_t TALER_rfc8785encode (char **inp) { -- cgit v1.2.3 From c014acf3c4ccf03109b0141d6b68d4f464464e19 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 10 May 2023 01:01:37 +0200 Subject: always use GNUNET_memcpy --- src/auditor/taler-helper-auditor-coins.c | 6 +-- src/auditor/taler-helper-auditor-wire.c | 24 ++++----- src/bank-lib/bank_api_transfer.c | 12 ++--- src/bank-lib/fakebank.c | 6 +-- src/exchange/taler-exchange-closer.c | 8 +-- src/exchange/taler-exchange-httpd.c | 6 +-- src/exchange/taler-exchange-transfer.c | 6 +-- src/exchangedb/bench_db.c | 12 ++--- src/exchangedb/pg_lookup_records_by_table.c | 6 +-- src/kyclogic/taler-exchange-kyc-tester.c | 6 +-- src/pq/pq_query_helper.c | 84 ++++++++++++++--------------- src/pq/pq_result_helper.c | 66 +++++++++++------------ src/templating/mustach.c | 6 +-- src/testing/test_bank_api_twisted.c | 6 +-- src/testing/testing_api_cmd_batch.c | 6 +-- src/testing/testing_api_loop.c | 6 +-- src/util/amount.c | 30 +++++------ src/util/crypto_confirmation.c | 6 +-- src/util/crypto_contract.c | 42 +++++++-------- src/util/crypto_helper_esign.c | 6 +-- src/util/crypto_helper_rsa.c | 12 ++--- src/util/exchange_signatures.c | 16 +++--- src/util/iban.c | 6 +-- src/util/payto.c | 6 +-- src/util/taler-exchange-secmod-cs.c | 24 ++++----- src/util/taler-exchange-secmod-eddsa.c | 6 +-- src/util/taler-exchange-secmod-rsa.c | 36 ++++++------- src/util/util.c | 6 +-- 28 files changed, 231 insertions(+), 231 deletions(-) (limited to 'src/util') diff --git a/src/auditor/taler-helper-auditor-coins.c b/src/auditor/taler-helper-auditor-coins.c index 7637e463..8edbcf29 100644 --- a/src/auditor/taler-helper-auditor-coins.c +++ b/src/auditor/taler-helper-auditor-coins.c @@ -172,9 +172,9 @@ coin_history_index (const struct TALER_CoinSpendPublicKeyP *coin_pub) { uint32_t i; - memcpy (&i, - coin_pub, - sizeof (i)); + GNUNET_memcpy (&i, + coin_pub, + sizeof (i)); return i % MAX_COIN_HISTORIES; } diff --git a/src/auditor/taler-helper-auditor-wire.c b/src/auditor/taler-helper-auditor-wire.c index 8615c439..bfc465b0 100644 --- a/src/auditor/taler-helper-auditor-wire.c +++ b/src/auditor/taler-helper-auditor-wire.c @@ -674,12 +674,12 @@ hash_rc (const char *receiver_account, size_t slen = strlen (receiver_account); char buf[sizeof (struct TALER_WireTransferIdentifierRawP) + slen]; - memcpy (buf, - wtid, - sizeof (*wtid)); - memcpy (&buf[sizeof (*wtid)], - receiver_account, - slen); + GNUNET_memcpy (buf, + wtid, + sizeof (*wtid)); + GNUNET_memcpy (&buf[sizeof (*wtid)], + receiver_account, + slen); GNUNET_CRYPTO_hash (buf, sizeof (buf), key); @@ -1504,9 +1504,9 @@ history_debit_cb (void *cls, roi->details.execution_date = dd->execution_date; roi->details.wtid = dd->wtid; roi->details.credit_account_uri = (const char *) &roi[1]; - memcpy (&roi[1], - dd->credit_account_uri, - slen); + GNUNET_memcpy (&roi[1], + dd->credit_account_uri, + slen); if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (out_map, &roi->subject_hash, @@ -1678,9 +1678,9 @@ reserve_in_cb (void *cls, rii->details.execution_date = execution_date; rii->details.reserve_pub = *reserve_pub; rii->details.debit_account_uri = (const char *) &rii[1]; - memcpy (&rii[1], - sender_account_details, - slen); + GNUNET_memcpy (&rii[1], + sender_account_details, + slen); GNUNET_CRYPTO_hash (&wire_reference, sizeof (uint64_t), &rii->row_off_hash); diff --git a/src/bank-lib/bank_api_transfer.c b/src/bank-lib/bank_api_transfer.c index 3b50018d..94d8c6b6 100644 --- a/src/bank-lib/bank_api_transfer.c +++ b/src/bank-lib/bank_api_transfer.c @@ -99,12 +99,12 @@ TALER_BANK_prepare_transfer ( wp->account_len = htonl ((uint32_t) d_len); wp->exchange_url_len = htonl ((uint32_t) u_len); end = (char *) &wp[1]; - memcpy (end, - destination_account_payto_uri, - d_len); - memcpy (end + d_len, - exchange_base_url, - u_len); + GNUNET_memcpy (end, + destination_account_payto_uri, + d_len); + GNUNET_memcpy (end + d_len, + exchange_base_url, + u_len); *buf = (char *) wp; } diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c index 60492e50..c916ad70 100644 --- a/src/bank-lib/fakebank.c +++ b/src/bank-lib/fakebank.c @@ -1389,9 +1389,9 @@ make_transfer ( if (NULL != timestamp) *timestamp = t->date; t->type = T_DEBIT; - memcpy (t->subject.debit.exchange_base_url, - exchange_base_url, - url_len); + GNUNET_memcpy (t->subject.debit.exchange_base_url, + exchange_base_url, + url_len); t->subject.debit.wtid = *subject; if (NULL == request_uid) GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE, diff --git a/src/exchange/taler-exchange-closer.c b/src/exchange/taler-exchange-closer.c index 41c6436a..63a98bd0 100644 --- a/src/exchange/taler-exchange-closer.c +++ b/src/exchange/taler-exchange-closer.c @@ -312,10 +312,10 @@ expired_reserve_cb (void *cls, memset (&wtid, 0, sizeof (wtid)); - memcpy (&wtid, - reserve_pub, - GNUNET_MIN (sizeof (wtid), - sizeof (*reserve_pub))); + GNUNET_memcpy (&wtid, + reserve_pub, + GNUNET_MIN (sizeof (wtid), + sizeof (*reserve_pub))); qs = db_plugin->insert_reserve_closed (db_plugin->cls, reserve_pub, now, diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index 97cf54c8..6c6398bc 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -932,9 +932,9 @@ proceed_with_handler (struct TEH_RequestContext *rc, /* Parse command-line arguments */ /* make a copy of 'url' because 'strtok_r()' will modify */ - memcpy (d, - url, - ulen); + GNUNET_memcpy (d, + url, + ulen); i = 0; args[i++] = strtok_r (d, "/", &sp); while ( (NULL != args[i - 1]) && diff --git a/src/exchange/taler-exchange-transfer.c b/src/exchange/taler-exchange-transfer.c index 5a4aace9..255fe76a 100644 --- a/src/exchange/taler-exchange-transfer.c +++ b/src/exchange/taler-exchange-transfer.c @@ -563,9 +563,9 @@ wire_prepare_cb (void *cls, } wpd = GNUNET_malloc (sizeof (struct WirePrepareData) + buf_size); - memcpy (&wpd[1], - buf, - buf_size); + GNUNET_memcpy (&wpd[1], + buf, + buf_size); wpd->buf_size = buf_size; wpd->row_id = rowid; GNUNET_CONTAINER_DLL_insert (wpd_head, diff --git a/src/exchangedb/bench_db.c b/src/exchangedb/bench_db.c index a85834d1..302d2306 100644 --- a/src/exchangedb/bench_db.c +++ b/src/exchangedb/bench_db.c @@ -169,9 +169,9 @@ bem_insert (struct GNUNET_PQ_Context *conn, GNUNET_CRYPTO_hash (&b, sizeof (b), &hc); - memcpy (&ihc, - &hc, - sizeof (ihc)); + GNUNET_memcpy (&ihc, + &hc, + sizeof (ihc)); { struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (&hc), @@ -265,9 +265,9 @@ bem_select (struct GNUNET_PQ_Context *conn, GNUNET_CRYPTO_hash (&b, sizeof (b), &hc); - memcpy (&ihc, - &hc, - sizeof (ihc)); + GNUNET_memcpy (&ihc, + &hc, + sizeof (ihc)); { struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_uint32 (&ihc), diff --git a/src/exchangedb/pg_lookup_records_by_table.c b/src/exchangedb/pg_lookup_records_by_table.c index efa0fec5..534e9a1d 100644 --- a/src/exchangedb/pg_lookup_records_by_table.c +++ b/src/exchangedb/pg_lookup_records_by_table.c @@ -1118,9 +1118,9 @@ lrbt_cb_table_refresh_transfer_keys (void *cls, ctx->error = true; return; } - memcpy (&td.details.refresh_transfer_keys.tprivs[0], - tpriv, - tpriv_size); + GNUNET_memcpy (&td.details.refresh_transfer_keys.tprivs[0], + tpriv, + tpriv_size); ctx->cb (ctx->cb_cls, &td); GNUNET_PQ_cleanup_result (rs); diff --git a/src/kyclogic/taler-exchange-kyc-tester.c b/src/kyclogic/taler-exchange-kyc-tester.c index 652d498c..c2efafd7 100644 --- a/src/kyclogic/taler-exchange-kyc-tester.c +++ b/src/kyclogic/taler-exchange-kyc-tester.c @@ -990,9 +990,9 @@ proceed_with_handler (struct TEKT_RequestContext *rc, /* Parse command-line arguments */ /* make a copy of 'url' because 'strtok_r()' will modify */ - memcpy (d, - url, - ulen); + GNUNET_memcpy (d, + url, + ulen); i = 0; args[i++] = strtok_r (d, "/", &sp); while ( (NULL != args[i - 1]) && diff --git a/src/pq/pq_query_helper.c b/src/pq/pq_query_helper.c index 1db608ed..2904b63f 100644 --- a/src/pq/pq_query_helper.c +++ b/src/pq/pq_query_helper.c @@ -202,21 +202,21 @@ qconv_denom_pub (void *cls, } len = tlen + sizeof (be); buf = GNUNET_malloc (len); - memcpy (buf, - be, - sizeof (be)); + GNUNET_memcpy (buf, + be, + sizeof (be)); switch (denom_pub->cipher) { case TALER_DENOMINATION_RSA: - memcpy (&buf[sizeof (be)], - tbuf, - tlen); + GNUNET_memcpy (&buf[sizeof (be)], + tbuf, + tlen); GNUNET_free (tbuf); break; case TALER_DENOMINATION_CS: - memcpy (&buf[sizeof (be)], - &denom_pub->details.cs_public_key, - tlen); + GNUNET_memcpy (&buf[sizeof (be)], + &denom_pub->details.cs_public_key, + tlen); break; default: GNUNET_assert (0); @@ -298,21 +298,21 @@ qconv_denom_sig (void *cls, } len = tlen + sizeof (be); buf = GNUNET_malloc (len); - memcpy (buf, - &be, - sizeof (be)); + GNUNET_memcpy (buf, + &be, + sizeof (be)); switch (denom_sig->cipher) { case TALER_DENOMINATION_RSA: - memcpy (&buf[sizeof (be)], - tbuf, - tlen); + GNUNET_memcpy (&buf[sizeof (be)], + tbuf, + tlen); GNUNET_free (tbuf); break; case TALER_DENOMINATION_CS: - memcpy (&buf[sizeof (be)], - &denom_sig->details.cs_signature, - tlen); + GNUNET_memcpy (&buf[sizeof (be)], + &denom_sig->details.cs_signature, + tlen); break; default: GNUNET_assert (0); @@ -394,21 +394,21 @@ qconv_blinded_denom_sig (void *cls, } len = tlen + sizeof (be); buf = GNUNET_malloc (len); - memcpy (buf, - &be, - sizeof (be)); + GNUNET_memcpy (buf, + &be, + sizeof (be)); switch (denom_sig->cipher) { case TALER_DENOMINATION_RSA: - memcpy (&buf[sizeof (be)], - tbuf, - tlen); + GNUNET_memcpy (&buf[sizeof (be)], + tbuf, + tlen); GNUNET_free (tbuf); break; case TALER_DENOMINATION_CS: - memcpy (&buf[sizeof (be)], - &denom_sig->details.blinded_cs_answer, - tlen); + GNUNET_memcpy (&buf[sizeof (be)], + &denom_sig->details.blinded_cs_answer, + tlen); break; default: GNUNET_assert (0); @@ -487,20 +487,20 @@ qconv_blinded_planchet (void *cls, } len = tlen + sizeof (be); buf = GNUNET_malloc (len); - memcpy (buf, - &be, - sizeof (be)); + GNUNET_memcpy (buf, + &be, + sizeof (be)); switch (bp->cipher) { case TALER_DENOMINATION_RSA: - memcpy (&buf[sizeof (be)], - bp->details.rsa_blinded_planchet.blinded_msg, - tlen); + GNUNET_memcpy (&buf[sizeof (be)], + bp->details.rsa_blinded_planchet.blinded_msg, + tlen); break; case TALER_DENOMINATION_CS: - memcpy (&buf[sizeof (be)], - &bp->details.cs_blinded_planchet, - tlen); + GNUNET_memcpy (&buf[sizeof (be)], + &bp->details.cs_blinded_planchet, + tlen); break; default: GNUNET_assert (0); @@ -578,17 +578,17 @@ qconv_exchange_withdraw_values (void *cls, } len = tlen + sizeof (be); buf = GNUNET_malloc (len); - memcpy (buf, - &be, - sizeof (be)); + GNUNET_memcpy (buf, + &be, + sizeof (be)); switch (alg_values->cipher) { case TALER_DENOMINATION_RSA: break; case TALER_DENOMINATION_CS: - memcpy (&buf[sizeof (be)], - &alg_values->details.cs_values, - tlen); + GNUNET_memcpy (&buf[sizeof (be)], + &alg_values->details.cs_values, + tlen); break; default: GNUNET_assert (0); diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c index 139cf1cb..9441412d 100644 --- a/src/pq/pq_result_helper.c +++ b/src/pq/pq_result_helper.c @@ -113,9 +113,9 @@ extract_amount_nbo_helper (PGresult *result, } len = GNUNET_MIN (TALER_CURRENCY_LEN - 1, strlen (currency)); - memcpy (r_amount_nbo->currency, - currency, - len); + GNUNET_memcpy (r_amount_nbo->currency, + currency, + len); return GNUNET_OK; } @@ -420,9 +420,9 @@ extract_denom_pub (void *cls, GNUNET_break (0); return GNUNET_SYSERR; } - memcpy (be, - res, - sizeof (be)); + GNUNET_memcpy (be, + res, + sizeof (be)); res += sizeof (be); len -= sizeof (be); pk->cipher = ntohl (be[0]); @@ -445,9 +445,9 @@ extract_denom_pub (void *cls, GNUNET_break (0); return GNUNET_SYSERR; } - memcpy (&pk->details.cs_public_key, - res, - len); + GNUNET_memcpy (&pk->details.cs_public_key, + res, + len); return GNUNET_OK; default: GNUNET_break (0); @@ -543,9 +543,9 @@ extract_denom_sig (void *cls, GNUNET_break (0); return GNUNET_SYSERR; } - memcpy (&be, - res, - sizeof (be)); + GNUNET_memcpy (&be, + res, + sizeof (be)); if (0x00 != ntohl (be[1])) { GNUNET_break (0); @@ -572,9 +572,9 @@ extract_denom_sig (void *cls, GNUNET_break (0); return GNUNET_SYSERR; } - memcpy (&sig->details.cs_signature, - res, - len); + GNUNET_memcpy (&sig->details.cs_signature, + res, + len); return GNUNET_OK; default: GNUNET_break (0); @@ -670,9 +670,9 @@ extract_blinded_denom_sig (void *cls, GNUNET_break (0); return GNUNET_SYSERR; } - memcpy (&be, - res, - sizeof (be)); + GNUNET_memcpy (&be, + res, + sizeof (be)); if (0x01 != ntohl (be[1])) /* magic marker: blinded */ { GNUNET_break (0); @@ -699,9 +699,9 @@ extract_blinded_denom_sig (void *cls, GNUNET_break (0); return GNUNET_SYSERR; } - memcpy (&sig->details.blinded_cs_answer, - res, - len); + GNUNET_memcpy (&sig->details.blinded_cs_answer, + res, + len); return GNUNET_OK; default: GNUNET_break (0); @@ -798,9 +798,9 @@ extract_blinded_planchet (void *cls, GNUNET_break (0); return GNUNET_SYSERR; } - memcpy (&be, - res, - sizeof (be)); + GNUNET_memcpy (&be, + res, + sizeof (be)); if (0x0100 != ntohl (be[1])) /* magic marker: blinded */ { GNUNET_break (0); @@ -824,9 +824,9 @@ extract_blinded_planchet (void *cls, GNUNET_break (0); return GNUNET_SYSERR; } - memcpy (&bp->details.cs_blinded_planchet, - res, - len); + GNUNET_memcpy (&bp->details.cs_blinded_planchet, + res, + len); return GNUNET_OK; default: GNUNET_break (0); @@ -923,9 +923,9 @@ extract_exchange_withdraw_values (void *cls, GNUNET_break (0); return GNUNET_SYSERR; } - memcpy (&be, - res, - sizeof (be)); + GNUNET_memcpy (&be, + res, + sizeof (be)); if (0x010000 != ntohl (be[1])) /* magic marker: EWV */ { GNUNET_break (0); @@ -949,9 +949,9 @@ extract_exchange_withdraw_values (void *cls, GNUNET_break (0); return GNUNET_SYSERR; } - memcpy (&alg_values->details.cs_values, - res, - len); + GNUNET_memcpy (&alg_values->details.cs_values, + res, + len); return GNUNET_OK; default: GNUNET_break (0); diff --git a/src/templating/mustach.c b/src/templating/mustach.c index caa80dcc..9797c533 100644 --- a/src/templating/mustach.c +++ b/src/templating/mustach.c @@ -297,7 +297,7 @@ static int process(const char *template, struct iwrap *iwrap, FILE *file, const #endif if (len > MUSTACH_MAX_LENGTH) return MUSTACH_ERROR_TAG_TOO_LONG; - memcpy(name, beg, len); + GNUNET_memcpy(name, beg, len); name[len] = 0; break; } @@ -317,7 +317,7 @@ static int process(const char *template, struct iwrap *iwrap, FILE *file, const return MUSTACH_ERROR_BAD_SEPARATORS; oplen = l; tmp = alloca(oplen + 1); - memcpy(tmp, beg, oplen); + GNUNET_memcpy(tmp, beg, oplen); tmp[oplen] = 0; opstr = tmp; while (l < len && isspace(beg[l])) l++; @@ -325,7 +325,7 @@ static int process(const char *template, struct iwrap *iwrap, FILE *file, const return MUSTACH_ERROR_BAD_SEPARATORS; cllen = len - l; tmp = alloca(cllen + 1); - memcpy(tmp, beg + l, cllen); + GNUNET_memcpy(tmp, beg + l, cllen); tmp[cllen] = 0; clstr = tmp; break; diff --git a/src/testing/test_bank_api_twisted.c b/src/testing/test_bank_api_twisted.c index 80629b6f..84379ad1 100644 --- a/src/testing/test_bank_api_twisted.c +++ b/src/testing/test_bank_api_twisted.c @@ -85,9 +85,9 @@ run (void *cls, memset (&wtid, 0x5a, sizeof (wtid)); - memcpy (&exchange_auth_twisted, - &bc.exchange_auth, - sizeof (struct TALER_BANK_AuthenticationData)); + GNUNET_memcpy (&exchange_auth_twisted, + &bc.exchange_auth, + sizeof (struct TALER_BANK_AuthenticationData)); if (with_fakebank) exchange_auth_twisted.wire_gateway_url = "http://localhost:8888/2/"; diff --git a/src/testing/testing_api_cmd_batch.c b/src/testing/testing_api_cmd_batch.c index a5263b03..d81a7767 100644 --- a/src/testing/testing_api_cmd_batch.c +++ b/src/testing/testing_api_cmd_batch.c @@ -150,9 +150,9 @@ TALER_TESTING_cmd_batch (const char *label, bs->batch = GNUNET_new_array (i + 1, struct TALER_TESTING_Command); - memcpy (bs->batch, - batch, - sizeof (struct TALER_TESTING_Command) * i); + GNUNET_memcpy (bs->batch, + batch, + sizeof (struct TALER_TESTING_Command) * i); { struct TALER_TESTING_Command cmd = { .cls = bs, diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c index 3ac9bea2..271b6e76 100644 --- a/src/testing/testing_api_loop.c +++ b/src/testing/testing_api_loop.c @@ -452,9 +452,9 @@ TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is, is->commands = GNUNET_malloc_large ( (i + 1) * sizeof (struct TALER_TESTING_Command)); GNUNET_assert (NULL != is->commands); - memcpy (is->commands, - commands, - sizeof (struct TALER_TESTING_Command) * i); + GNUNET_memcpy (is->commands, + commands, + sizeof (struct TALER_TESTING_Command) * i); is->timeout_task = GNUNET_SCHEDULER_add_delayed ( timeout, &do_timeout, diff --git a/src/util/amount.c b/src/util/amount.c index d5698e8b..dfe10b07 100644 --- a/src/util/amount.c +++ b/src/util/amount.c @@ -72,9 +72,9 @@ TALER_string_to_amount (const char *str, } GNUNET_assert (TALER_CURRENCY_LEN > (colon - str)); - memcpy (amount->currency, - str, - colon - str); + GNUNET_memcpy (amount->currency, + str, + colon - str); /* 0-terminate *and* normalize buffer by setting everything to '\0' */ memset (&amount->currency [colon - str], 0, @@ -193,9 +193,9 @@ TALER_amount_hton (struct TALER_AmountNBO *res, TALER_amount_is_valid (d)); res->value = GNUNET_htonll (d->value); res->fraction = htonl (d->fraction); - memcpy (res->currency, - d->currency, - TALER_CURRENCY_LEN); + GNUNET_memcpy (res->currency, + d->currency, + TALER_CURRENCY_LEN); } @@ -205,9 +205,9 @@ TALER_amount_ntoh (struct TALER_Amount *res, { res->value = GNUNET_ntohll (dn->value); res->fraction = ntohl (dn->fraction); - memcpy (res->currency, - dn->currency, - TALER_CURRENCY_LEN); + GNUNET_memcpy (res->currency, + dn->currency, + TALER_CURRENCY_LEN); GNUNET_assert (GNUNET_YES == TALER_amount_is_valid (res)); } @@ -225,9 +225,9 @@ TALER_amount_set_zero (const char *cur, memset (amount, 0, sizeof (struct TALER_Amount)); - memcpy (amount->currency, - cur, - slen); + GNUNET_memcpy (amount->currency, + cur, + slen); return GNUNET_OK; } @@ -680,9 +680,9 @@ TALER_amount_multiply (struct TALER_Amount *result, if (GNUNET_SYSERR == TALER_amount_normalize (&in)) return TALER_AAR_INVALID_NORMALIZATION_FAILED; - memcpy (result->currency, - amount->currency, - TALER_CURRENCY_LEN); + GNUNET_memcpy (result->currency, + amount->currency, + TALER_CURRENCY_LEN); if ( (0 == factor) || ( (0 == in.value) && (0 == in.fraction) ) ) diff --git a/src/util/crypto_confirmation.c b/src/util/crypto_confirmation.c index e52562e3..bbdf701e 100644 --- a/src/util/crypto_confirmation.c +++ b/src/util/crypto_confirmation.c @@ -90,9 +90,9 @@ compute_totp (struct GNUNET_TIME_Timestamp ts, mc = gcry_md_read (md, GCRY_MD_SHA1); GNUNET_assert (NULL != mc); - memcpy (hmac, - mc, - sizeof (hmac)); + GNUNET_memcpy (hmac, + mc, + sizeof (hmac)); gcry_md_close (md); } diff --git a/src/util/crypto_contract.c b/src/util/crypto_contract.c index 3bfe9eb8..bec34c98 100644 --- a/src/util/crypto_contract.c +++ b/src/util/crypto_contract.c @@ -131,9 +131,9 @@ blob_encrypt (const struct NonceP *nonce, + data_size; *res_size = ciphertext_size; *res = GNUNET_malloc (ciphertext_size); - memcpy (*res, - nonce, - crypto_secretbox_NONCEBYTES); + GNUNET_memcpy (*res, + nonce, + crypto_secretbox_NONCEBYTES); GNUNET_assert (0 == crypto_secretbox_easy (*res + crypto_secretbox_NONCEBYTES, data, @@ -274,9 +274,9 @@ TALER_CRYPTO_contract_encrypt_for_merge ( hdr->header.ctype = htonl (TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER); hdr->header.clen = htonl ((uint32_t) clen); hdr->merge_priv = *merge_priv; - memcpy (&hdr[1], - xbuf, - cbuf_size); + GNUNET_memcpy (&hdr[1], + xbuf, + cbuf_size); GNUNET_free (xbuf); GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &nonce, @@ -423,9 +423,9 @@ TALER_CRYPTO_contract_encrypt_for_deposit ( hdr = GNUNET_malloc (sizeof (*hdr) + cbuf_size); hdr->ctype = htonl (TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST); hdr->clen = htonl ((uint32_t) clen); - memcpy (&hdr[1], - xbuf, - cbuf_size); + GNUNET_memcpy (&hdr[1], + xbuf, + cbuf_size); GNUNET_free (xbuf); GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &nonce, @@ -441,12 +441,12 @@ TALER_CRYPTO_contract_encrypt_for_deposit ( GNUNET_free (hdr); /* prepend purse_pub */ *econtract = GNUNET_malloc (xecontract_size + sizeof (*purse_pub)); - memcpy (*econtract, - purse_pub, - sizeof (*purse_pub)); - memcpy (sizeof (*purse_pub) + *econtract, - xecontract, - xecontract_size); + GNUNET_memcpy (*econtract, + purse_pub, + sizeof (*purse_pub)); + GNUNET_memcpy (sizeof (*purse_pub) + *econtract, + xecontract, + xecontract_size); *econtract_size = xecontract_size + sizeof (*purse_pub); GNUNET_free (xecontract); } @@ -573,9 +573,9 @@ TALER_CRYPTO_kyc_attributes_encrypt ( cbuf_size = compressBound (clen); xbuf = GNUNET_malloc (cbuf_size + sizeof (uint32_t)); belen = htonl ((uint32_t) clen); - memcpy (xbuf, - &belen, - sizeof (belen)); + GNUNET_memcpy (xbuf, + &belen, + sizeof (belen)); ret = compress (xbuf + 4, &cbuf_size, (const Bytef *) cstr, @@ -623,9 +623,9 @@ TALER_CRYPTO_kyc_attributes_decrypt ( GNUNET_break_op (0); return NULL; } - memcpy (&belen, - xhdr, - sizeof (belen)); + GNUNET_memcpy (&belen, + xhdr, + sizeof (belen)); clen = ntohl (belen); if (clen >= GNUNET_MAX_MALLOC_CHECKED) { diff --git a/src/util/crypto_helper_esign.c b/src/util/crypto_helper_esign.c index 5a9ad74e..5b04d0ea 100644 --- a/src/util/crypto_helper_esign.c +++ b/src/util/crypto_helper_esign.c @@ -357,9 +357,9 @@ TALER_CRYPTO_helper_esign_sign_ ( sr->header.size = htons (sizeof (buf)); sr->header.type = htons (TALER_HELPER_EDDSA_MT_REQ_SIGN); sr->reserved = htonl (0); - memcpy (&sr->purpose, - purpose, - purpose_size); + GNUNET_memcpy (&sr->purpose, + purpose, + purpose_size); if (GNUNET_OK != TALER_crypto_helper_send_all (esh->sock, buf, diff --git a/src/util/crypto_helper_rsa.c b/src/util/crypto_helper_rsa.c index efded50a..4098a846 100644 --- a/src/util/crypto_helper_rsa.c +++ b/src/util/crypto_helper_rsa.c @@ -417,9 +417,9 @@ TALER_CRYPTO_helper_rsa_sign ( sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN); sr->reserved = htonl (0); sr->h_rsa = *rsr->h_rsa; - memcpy (&sr[1], - rsr->msg, - rsr->msg_size); + GNUNET_memcpy (&sr[1], + rsr->msg, + rsr->msg_size); if (GNUNET_OK != TALER_crypto_helper_send_all (dh->sock, buf, @@ -655,9 +655,9 @@ TALER_CRYPTO_helper_rsa_batch_sign ( sr->header.size = htons (sizeof (*sr) + rsr->msg_size); sr->reserved = htonl (0); sr->h_rsa = *rsr->h_rsa; - memcpy (&sr[1], - rsr->msg, - rsr->msg_size); + GNUNET_memcpy (&sr[1], + rsr->msg, + rsr->msg_size); wbuf += sizeof (*sr) + rsr->msg_size; } GNUNET_assert (wbuf == &obuf[mlen]); diff --git a/src/util/exchange_signatures.c b/src/util/exchange_signatures.c index d8bf716c..6f8ebdaf 100644 --- a/src/util/exchange_signatures.c +++ b/src/util/exchange_signatures.c @@ -1177,10 +1177,10 @@ TALER_exchange_online_denomination_expired_sign ( }; /* strncpy would create a compiler warning */ - memcpy (dua.operation, - op, - GNUNET_MIN (sizeof (dua.operation), - strlen (op))); + GNUNET_memcpy (dua.operation, + op, + GNUNET_MIN (sizeof (dua.operation), + strlen (op))); return scb (&dua.purpose, pub, sig); @@ -1204,10 +1204,10 @@ TALER_exchange_online_denomination_expired_verify ( }; /* strncpy would create a compiler warning */ - memcpy (dua.operation, - op, - GNUNET_MIN (sizeof (dua.operation), - strlen (op))); + GNUNET_memcpy (dua.operation, + op, + GNUNET_MIN (sizeof (dua.operation), + strlen (op))); return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED, &dua, diff --git a/src/util/iban.c b/src/util/iban.c index efd8c428..c2274d3c 100644 --- a/src/util/iban.c +++ b/src/util/iban.c @@ -233,9 +233,9 @@ TALER_iban_validate (const char *iban) return GNUNET_strdup ("IBAN number too short to be valid"); if (len > 34) return GNUNET_strdup ("IBAN number too long to be valid"); - memcpy (cc, iban, 2); - memcpy (ibancpy, iban + 4, len - 4); - memcpy (ibancpy + len - 4, iban, 4); + GNUNET_memcpy (cc, iban, 2); + GNUNET_memcpy (ibancpy, iban + 4, len - 4); + GNUNET_memcpy (ibancpy + len - 4, iban, 4); ibancpy[len] = '\0'; cc_entry.code = cc; cc_entry.english = NULL; diff --git a/src/util/payto.c b/src/util/payto.c index 81664b1d..9b0e83e8 100644 --- a/src/util/payto.c +++ b/src/util/payto.c @@ -267,9 +267,9 @@ TALER_payto_hash (const char *payto, &sha512); GNUNET_static_assert (sizeof (sha512) > sizeof (*h_payto)); /* truncate */ - memcpy (h_payto, - &sha512, - sizeof (*h_payto)); + GNUNET_memcpy (h_payto, + &sha512, + sizeof (*h_payto)); } diff --git a/src/util/taler-exchange-secmod-cs.c b/src/util/taler-exchange-secmod-cs.c index 2cdf09ad..ed0eba15 100644 --- a/src/util/taler-exchange-secmod-cs.c +++ b/src/util/taler-exchange-secmod-cs.c @@ -423,9 +423,9 @@ generate_response (struct DenominationKey *dk) &an->secm_sig); an->secm_pub = TES_smpub; p = (void *) &an[1]; - memcpy (p, - denom->section, - nlen); + GNUNET_memcpy (p, + denom->section, + nlen); dk->an = an; } @@ -1373,9 +1373,9 @@ cs_client_init (struct TES_Client *client) NULL != dk; dk = dk->next) { - memcpy (&buf[obs], - dk->an, - ntohs (dk->an->header.size)); + GNUNET_memcpy (&buf[obs], + dk->an, + ntohs (dk->an->header.size)); obs += ntohs (dk->an->header.size); } } @@ -1472,18 +1472,18 @@ cs_update_client_keys (struct TES_Client *client) .h_cs = key->h_cs }; - memcpy (&buf[obs], - &pn, - sizeof (pn)); + GNUNET_memcpy (&buf[obs], + &pn, + sizeof (pn)); GNUNET_assert (obs + sizeof (pn) > obs); obs += sizeof (pn); } else { - memcpy (&buf[obs], - key->an, - ntohs (key->an->header.size)); + GNUNET_memcpy (&buf[obs], + key->an, + ntohs (key->an->header.size)); GNUNET_assert (obs + ntohs (key->an->header.size) > obs); obs += ntohs (key->an->header.size); diff --git a/src/util/taler-exchange-secmod-eddsa.c b/src/util/taler-exchange-secmod-eddsa.c index e07e9a71..3b78e71d 100644 --- a/src/util/taler-exchange-secmod-eddsa.c +++ b/src/util/taler-exchange-secmod-eddsa.c @@ -826,9 +826,9 @@ parse_key (const char *filename, filename); return GNUNET_SYSERR; } - memcpy (&priv, - buf, - buf_size); + GNUNET_memcpy (&priv, + buf, + buf_size); { struct GNUNET_CRYPTO_EddsaPublicKey pub; diff --git a/src/util/taler-exchange-secmod-rsa.c b/src/util/taler-exchange-secmod-rsa.c index c651d78a..414cb4ac 100644 --- a/src/util/taler-exchange-secmod-rsa.c +++ b/src/util/taler-exchange-secmod-rsa.c @@ -394,13 +394,13 @@ generate_response (struct DenominationKey *dk) &an->secm_sig); an->secm_pub = TES_smpub; p = (void *) &an[1]; - memcpy (p, - buf, - buf_len); + GNUNET_memcpy (p, + buf, + buf_len); GNUNET_free (buf); - memcpy (p + buf_len, - denom->section, - nlen); + GNUNET_memcpy (p + buf_len, + denom->section, + nlen); dk->an = an; } @@ -524,9 +524,9 @@ send_signature (struct TES_Client *client, sr = GNUNET_malloc (tsize); sr->header.size = htons (tsize); sr->header.type = htons (TALER_HELPER_RSA_MT_RES_SIGNATURE); - memcpy (&sr[1], - buf, - buf_size); + GNUNET_memcpy (&sr[1], + buf, + buf_size); GNUNET_free (buf); ret = TES_transmit (client->csock, &sr->header); @@ -1111,9 +1111,9 @@ rsa_client_init (struct TES_Client *client) NULL != dk; dk = dk->next) { - memcpy (&buf[obs], - dk->an, - ntohs (dk->an->header.size)); + GNUNET_memcpy (&buf[obs], + dk->an, + ntohs (dk->an->header.size)); GNUNET_assert (obs + ntohs (dk->an->header.size) > obs); obs += ntohs (dk->an->header.size); @@ -1212,18 +1212,18 @@ rsa_update_client_keys (struct TES_Client *client) .h_rsa = key->h_rsa }; - memcpy (&buf[obs], - &pn, - sizeof (pn)); + GNUNET_memcpy (&buf[obs], + &pn, + sizeof (pn)); GNUNET_assert (obs + sizeof (pn) > obs); obs += sizeof (pn); } else { - memcpy (&buf[obs], - key->an, - ntohs (key->an->header.size)); + GNUNET_memcpy (&buf[obs], + key->an, + ntohs (key->an->header.size)); GNUNET_assert (obs + ntohs (key->an->header.size) > obs); obs += ntohs (key->an->header.size); diff --git a/src/util/util.c b/src/util/util.c index 82c5f7f3..da572748 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -41,9 +41,9 @@ TALER_b2s (const void *buf, &hc); tmp = GNUNET_STRINGS_data_to_string_alloc (&hc, sizeof (hc)); - memcpy (ret, - tmp, - 8); + GNUNET_memcpy (ret, + tmp, + 8); GNUNET_free (tmp); ret[8] = '\0'; return ret; -- cgit v1.2.3 From cc34502ac11a0fc77eb68a469b037fe2e2ee6c20 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 10 May 2023 01:13:45 +0200 Subject: -fix TOTP calculation --- src/util/crypto_confirmation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/util') diff --git a/src/util/crypto_confirmation.c b/src/util/crypto_confirmation.c index bbdf701e..a238d537 100644 --- a/src/util/crypto_confirmation.c +++ b/src/util/crypto_confirmation.c @@ -102,7 +102,7 @@ compute_totp (struct GNUNET_TIME_Timestamp ts, offset = hmac[sizeof (hmac) - 1] & 0x0f; for (int count = 0; count < 4; count++) - code |= hmac[offset + 3 - count] << (8 * count); + code |= ((uint32_t) hmac[offset + 3 - count]) << (8 * count); code &= 0x7fffffff; /* always use 8 digits (maximum) */ code = code % 100000000; -- cgit v1.2.3 From 495496340554ec4699e9dbc561d921b242c92e6d Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 10 May 2023 09:13:09 +0200 Subject: ensure amounts are in upper-case --- src/util/amount.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'src/util') diff --git a/src/util/amount.c b/src/util/amount.c index dfe10b07..9cd0739c 100644 --- a/src/util/amount.c +++ b/src/util/amount.c @@ -72,9 +72,8 @@ TALER_string_to_amount (const char *str, } GNUNET_assert (TALER_CURRENCY_LEN > (colon - str)); - GNUNET_memcpy (amount->currency, - str, - colon - str); + for (unsigned int i = 0; icurrency[i] = toupper (str[i]); /* 0-terminate *and* normalize buffer by setting everything to '\0' */ memset (&amount->currency [colon - str], 0, @@ -193,9 +192,8 @@ TALER_amount_hton (struct TALER_AmountNBO *res, TALER_amount_is_valid (d)); res->value = GNUNET_htonll (d->value); res->fraction = htonl (d->fraction); - GNUNET_memcpy (res->currency, - d->currency, - TALER_CURRENCY_LEN); + for (unsigned int i = 0; icurrency[i] = toupper (d->currency[i]); } @@ -225,9 +223,8 @@ TALER_amount_set_zero (const char *cur, memset (amount, 0, sizeof (struct TALER_Amount)); - GNUNET_memcpy (amount->currency, - cur, - slen); + for (unsigned int i = 0; icurrency[i] = toupper (cur[i]); return GNUNET_OK; } -- cgit v1.2.3 From b15713f42e9ecbc67e9b8ffd178d97d08b7377bb Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 10 May 2023 22:09:47 +0200 Subject: add helper logic for JSON2JSON conversion --- src/include/taler_util.h | 54 +++++- src/util/Makefile.am | 13 +- src/util/conversion.c | 402 ++++++++++++++++++++++++++++++++++++++++++++ src/util/test_conversion.c | 149 ++++++++++++++++ src/util/test_conversion.sh | 5 + 5 files changed, 621 insertions(+), 2 deletions(-) create mode 100644 src/util/conversion.c create mode 100644 src/util/test_conversion.c create mode 100755 src/util/test_conversion.sh (limited to 'src/util') diff --git a/src/include/taler_util.h b/src/include/taler_util.h index 6c294822..0b15eb8a 100644 --- a/src/include/taler_util.h +++ b/src/include/taler_util.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2021 Taler Systems SA + Copyright (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -569,6 +569,58 @@ enum GNUNET_GenericReturnValue TALER_JSON_parse_age_groups (const json_t *root, struct TALER_AgeMask *mask); + +/** + * Handle to an external process that will assist + * with some JSON-to-JSON conversion. + */ +struct TALER_JSON_ExternalConversion; + +/** + * Type of a callback that receives a JSON @a result. + * + * @param cls closure + * @param status_type how did the process die + * @apram code termination status code from the process + * @param result some JSON result, NULL if we failed to get an JSON output + */ +typedef void +(*TALER_JSON_JsonCallback) (void *cls, + enum GNUNET_OS_ProcessStatusType status_type, + unsigned long code, + const json_t *result); + + +/** + * Launch some external helper @a binary to convert some @a input + * and eventually call @a cb with the result. + * + * @param input JSON to serialize and pass to the helper process + * @param cb function to call on the result + * @param cb_cls closure for @a cb + * @param binary name of the binary to execute + * @param ... NULL-terminated list of arguments for the @a binary, + * usually starting with again the name of the binary + * @return handle to cancel the operation (and kill the helper) + */ +struct TALER_JSON_ExternalConversion * +TALER_JSON_external_conversion_start (const json_t *input, + TALER_JSON_JsonCallback cb, + void *cb_cls, + const char *binary, + ...); + +/** + * Abort external conversion, killing the process and preventing + * the callback from being called. Must not be called after the + * callback was invoked. + * + * @param[in] ec external conversion handle to cancel + */ +void +TALER_JSON_external_conversion_stop ( + struct TALER_JSON_ExternalConversion *ec); + #undef __TALER_UTIL_LIB_H_INSIDE__ #endif diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 115ea505..9d1ec9d4 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -20,7 +20,8 @@ EXTRA_DIST = \ taler-config.in \ test_helper_eddsa.conf \ test_helper_rsa.conf \ - test_helper_cs.conf + test_helper_cs.conf \ + test_conversion.sh bin_PROGRAMS = \ taler-exchange-secmod-eddsa \ @@ -80,6 +81,7 @@ libtalerutil_la_SOURCES = \ aml_signatures.c \ auditor_signatures.c \ config.c \ + conversion.c \ crypto.c \ crypto_confirmation.c \ crypto_contract.c \ @@ -125,6 +127,7 @@ AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH= check_PROGRAMS = \ test_age_restriction \ test_amount \ + test_conversion \ test_crypto \ test_helper_eddsa \ test_helper_rsa \ @@ -141,6 +144,14 @@ test_age_restriction_LDADD = \ -lgnunetutil \ libtalerutil.la +test_conversion_SOURCES = \ + test_conversion.c +test_conversion_LDADD = \ + -lgnunetjson \ + -lgnunetutil \ + -ljansson \ + libtalerutil.la + test_amount_SOURCES = \ test_amount.c test_amount_LDADD = \ diff --git a/src/util/conversion.c b/src/util/conversion.c new file mode 100644 index 00000000..501ca014 --- /dev/null +++ b/src/util/conversion.c @@ -0,0 +1,402 @@ +/* + This file is part of TALER + Copyright (C) 2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see +*/ +/** + * @file conversion.c + * @brief helper routines to run some external JSON-to-JSON converter + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include + + +struct TALER_JSON_ExternalConversion +{ + /** + * Callback to call with the result. + */ + TALER_JSON_JsonCallback cb; + + /** + * Closure for @e cb. + */ + void *cb_cls; + + /** + * Handle to the helper process. + */ + struct GNUNET_OS_Process *helper; + + /** + * Pipe for the stdin of the @e helper. + */ + struct GNUNET_DISK_FileHandle *chld_stdin; + + /** + * Pipe for the stdout of the @e helper. + */ + struct GNUNET_DISK_FileHandle *chld_stdout; + + /** + * Handle to wait on the child to terminate. + */ + struct GNUNET_ChildWaitHandle *cwh; + + /** + * Task to read JSON output from the child. + */ + struct GNUNET_SCHEDULER_Task *read_task; + + /** + * Task to send JSON input to the child. + */ + struct GNUNET_SCHEDULER_Task *write_task; + + /** + * Buffer with data we need to send to the helper. + */ + void *write_buf; + + /** + * Buffer for reading data from the helper. + */ + void *read_buf; + + /** + * Total length of @e write_buf. + */ + size_t write_size; + + /** + * Current write position in @e write_buf. + */ + size_t write_pos; + + /** + * Current size of @a read_buf. + */ + size_t read_size; + + /** + * Current offset in @a read_buf. + */ + size_t read_pos; + +}; + + +/** + * Function called when we can read more data from + * the child process. + * + * @param cls our `struct TALER_JSON_ExternalConversion *` + */ +static void +read_cb (void *cls) +{ + struct TALER_JSON_ExternalConversion *ec = cls; + + ec->read_task = NULL; + while (1) + { + ssize_t ret; + + if (ec->read_size == ec->read_pos) + { + /* Grow input buffer */ + size_t ns; + void *tmp; + + ns = GNUNET_MAX (2 * ec->read_size, + 1024); + if (ns > GNUNET_MAX_MALLOC_CHECKED) + ns = GNUNET_MAX_MALLOC_CHECKED; + if (ec->read_size == ns) + { + /* Helper returned more than 40 MB of data! Stop reading! */ + GNUNET_break (0); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (ec->chld_stdin)); + return; + } + tmp = GNUNET_malloc_large (ns); + if (NULL == tmp) + { + /* out of memory, also stop reading */ + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "malloc"); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (ec->chld_stdin)); + return; + } + GNUNET_memcpy (tmp, + ec->read_buf, + ec->read_pos); + GNUNET_free (ec->read_buf); + ec->read_buf = tmp; + ec->read_size = ns; + } + ret = GNUNET_DISK_file_read (ec->chld_stdout, + ec->read_buf, + ec->read_size - ec->read_pos); + if (ret < 0) + { + if ( (EAGAIN != errno) && + (EWOULDBLOCK != errno) && + (EINTR != errno) ) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "read"); + return; + } + break; + } + if (0 == ret) + { + /* regular end of stream, good! */ + return; + } + GNUNET_assert (ec->read_size >= ec->read_pos + ret); + ec->read_pos += ret; + } + ec->read_task + = GNUNET_SCHEDULER_add_read_file ( + GNUNET_TIME_UNIT_FOREVER_REL, + ec->chld_stdout, + &read_cb, + ec); +} + + +/** + * Function called when we can write more data to + * the child process. + * + * @param cls our `struct TALER_JSON_ExternalConversion *` + */ +static void +write_cb (void *cls) +{ + struct TALER_JSON_ExternalConversion *ec = cls; + ssize_t ret; + + ec->write_task = NULL; + while (ec->write_size > ec->write_pos) + { + ret = GNUNET_DISK_file_write (ec->chld_stdin, + ec->write_buf + ec->write_pos, + ec->write_size - ec->write_pos); + if (ret < 0) + { + if ( (EAGAIN != errno) && + (EINTR != errno) ) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "write"); + break; + } + if (0 == ret) + { + GNUNET_break (0); + break; + } + GNUNET_assert (ec->write_size >= ec->write_pos + ret); + ec->write_pos += ret; + } + if ( (ec->write_size > ec->write_pos) && + ( (EAGAIN == errno) || + (EWOULDBLOCK == errno) || + (EINTR == errno) ) ) + { + ec->write_task + = GNUNET_SCHEDULER_add_write_file ( + GNUNET_TIME_UNIT_FOREVER_REL, + ec->chld_stdin, + &write_cb, + ec); + } + else + { + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (ec->chld_stdin)); + ec->chld_stdin = NULL; + } +} + + +/** + * Defines a GNUNET_ChildCompletedCallback which is sent back + * upon death or completion of a child process. + * + * @param cls handle for the callback + * @param type type of the process + * @param exit_code status code of the process + * + */ +static void +child_done_cb (void *cls, + enum GNUNET_OS_ProcessStatusType type, + long unsigned int exit_code) +{ + struct TALER_JSON_ExternalConversion *ec = cls; + json_t *j; + json_error_t err; + + ec->cwh = NULL; + if (NULL != ec->read_task) + { + GNUNET_SCHEDULER_cancel (ec->read_task); + /* We could get the process termination notification before having drained + the read buffer. So drain it now, just in case. */ + read_cb (ec); + } + if (NULL != ec->read_task) + { + GNUNET_SCHEDULER_cancel (ec->read_task); + ec->read_task = NULL; + } + GNUNET_OS_process_destroy (ec->helper); + ec->helper = NULL; + j = json_loadb (ec->read_buf, + ec->read_pos, + JSON_REJECT_DUPLICATES, + &err); + if (NULL == j) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to parse JSON from helper at %d: %s\n", + err.position, + err.text); + } + ec->cb (ec->cb_cls, + type, + exit_code, + j); + json_decref (j); + TALER_JSON_external_conversion_stop (ec); +} + + +struct TALER_JSON_ExternalConversion * +TALER_JSON_external_conversion_start (const json_t *input, + TALER_JSON_JsonCallback cb, + void *cb_cls, + const char *binary, + ...) +{ + struct TALER_JSON_ExternalConversion *ec; + struct GNUNET_DISK_PipeHandle *pipe_stdin; + struct GNUNET_DISK_PipeHandle *pipe_stdout; + va_list ap; + + ec = GNUNET_new (struct TALER_JSON_ExternalConversion); + ec->cb = cb; + ec->cb_cls = cb_cls; + pipe_stdin = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_READ); + GNUNET_assert (NULL != pipe_stdin); + pipe_stdout = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_WRITE); + GNUNET_assert (NULL != pipe_stdout); + va_start (ap, + binary); + ec->helper = GNUNET_OS_start_process_va (GNUNET_OS_INHERIT_STD_ERR, + pipe_stdin, + pipe_stdout, + NULL, + binary, + ap); + va_end (ap); + if (NULL == ec->helper) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to run conversion helper `%s'\n", + binary); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_pipe_close (pipe_stdin)); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_pipe_close (pipe_stdout)); + GNUNET_free (ec); + return NULL; + } + ec->chld_stdin = + GNUNET_DISK_pipe_detach_end (pipe_stdin, + GNUNET_DISK_PIPE_END_WRITE); + ec->chld_stdout = + GNUNET_DISK_pipe_detach_end (pipe_stdout, + GNUNET_DISK_PIPE_END_READ); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_pipe_close (pipe_stdin)); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_pipe_close (pipe_stdout)); + ec->write_buf = json_dumps (input, JSON_COMPACT); + ec->write_size = strlen (ec->write_buf); + ec->read_task + = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + ec->chld_stdout, + &read_cb, + ec); + ec->write_task + = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + ec->chld_stdin, + &write_cb, + ec); + ec->cwh = GNUNET_wait_child (ec->helper, + &child_done_cb, + ec); + return ec; +} + + +void +TALER_JSON_external_conversion_stop ( + struct TALER_JSON_ExternalConversion *ec) +{ + if (NULL != ec->cwh) + { + GNUNET_wait_child_cancel (ec->cwh); + ec->cwh = NULL; + } + if (NULL != ec->helper) + { + GNUNET_break (0 == + GNUNET_OS_process_kill (ec->helper, + SIGKILL)); + GNUNET_OS_process_destroy (ec->helper); + } + if (NULL != ec->read_task) + { + GNUNET_SCHEDULER_cancel (ec->read_task); + ec->read_task = NULL; + } + if (NULL != ec->write_task) + { + GNUNET_SCHEDULER_cancel (ec->write_task); + ec->write_task = NULL; + } + if (NULL != ec->chld_stdin) + { + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (ec->chld_stdin)); + ec->chld_stdin = NULL; + } + if (NULL != ec->chld_stdout) + { + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (ec->chld_stdout)); + ec->chld_stdout = NULL; + } + GNUNET_free (ec->read_buf); + free (ec->write_buf); + GNUNET_free (ec); +} diff --git a/src/util/test_conversion.c b/src/util/test_conversion.c new file mode 100644 index 00000000..00cb35e7 --- /dev/null +++ b/src/util/test_conversion.c @@ -0,0 +1,149 @@ +/* + This file is part of TALER + (C) 2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see +*/ +/** + * @file util/test_conversion.c + * @brief Tests for conversion logic + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include + +/** + * Return value from main(). + */ +static int global_ret; + +/** + * Handle to our helper. + */ +static struct TALER_JSON_ExternalConversion *ec; + + +/** + * Type of a callback that receives a JSON @a result. + * + * @param cls closure + * @param status_type how did the process die + * @apram code termination status code from the process + * @param result some JSON result, NULL if we failed to get an JSON output + */ +static void +conv_cb (void *cls, + enum GNUNET_OS_ProcessStatusType status_type, + unsigned long code, + const json_t *result) +{ + json_t *expect; + + (void) cls; + (void) status_type; + ec = NULL; + global_ret = 3; + if (42 != code) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected return value from helper: %u\n", + (unsigned int) code); + return; + } + expect = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("foo", + "arg") + ); + if (1 == json_equal (expect, + result)) + { + global_ret = 0; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected JSON result\n"); + json_dumpf (result, + stderr, + JSON_INDENT (2)); + global_ret = 4; + } + json_decref (expect); +} + + +/** + * Function called on shutdown/CTRL-C. + * + * @param cls NULL + */ +static void +do_shutdown (void *cls) +{ + (void) cls; + if (NULL != ec) + { + GNUNET_break (0); + global_ret = 2; + TALER_JSON_external_conversion_stop (ec); + ec = NULL; + } +} + + +/** + * Main test function. + * + * @param cls NULL + */ +static void +run (void *cls) +{ + json_t *input; + + (void) cls; + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, + NULL); + input = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("key", + "foo") + ); + ec = TALER_JSON_external_conversion_start (input, + &conv_cb, + NULL, + "./test_conversion.sh", + "test_conversion.sh", + "arg", + NULL); + json_decref (input); + GNUNET_assert (NULL != ec); +} + + +int +main (int argc, + const char *const argv[]) +{ + (void) argc; + (void) argv; + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + GNUNET_log_setup ("test-conversion", + "WARNING", + NULL); + GNUNET_OS_init (TALER_project_data_default ()); + global_ret = 1; + GNUNET_SCHEDULER_run (&run, + NULL); + return global_ret; +} diff --git a/src/util/test_conversion.sh b/src/util/test_conversion.sh new file mode 100755 index 00000000..26e1a36d --- /dev/null +++ b/src/util/test_conversion.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +KEY=$(jq -r .key) +echo -n "{\"$KEY\":\"$1\"}" +exit 42 -- cgit v1.2.3 From 7899bc5621d7f5040e2938b034705a7e3569f31d Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 11 May 2023 01:18:24 +0200 Subject: externalize persona JSON conversion logic, expand with file download --- src/kyclogic/Makefile.am | 6 +- src/kyclogic/kyclogic-persona.conf | 4 + src/kyclogic/plugin_kyclogic_persona.c | 374 ++++++++++----------- .../taler-exchange-kyc-persona-converter.sh | 54 +++ src/util/.gitignore | 1 + 5 files changed, 235 insertions(+), 204 deletions(-) create mode 100755 src/kyclogic/taler-exchange-kyc-persona-converter.sh (limited to 'src/util') diff --git a/src/kyclogic/Makefile.am b/src/kyclogic/Makefile.am index 858331f3..20430a4e 100644 --- a/src/kyclogic/Makefile.am +++ b/src/kyclogic/Makefile.am @@ -16,7 +16,11 @@ pkgcfg_DATA = \ EXTRA_DIST = \ $(pkgcfg_DATA) \ - sample.conf + sample.conf \ + persona-sample-reply.json + +bin_SCRIPTS = \ + taler-exchange-kyc-persona-converter.sh lib_LTLIBRARIES = \ libtalerkyclogic.la diff --git a/src/kyclogic/kyclogic-persona.conf b/src/kyclogic/kyclogic-persona.conf index 7f02bf49..2d52a9ee 100644 --- a/src/kyclogic/kyclogic-persona.conf +++ b/src/kyclogic/kyclogic-persona.conf @@ -29,6 +29,10 @@ KYC_PERSONA_SUBDOMAIN = taler # Authentication token to use. KYC_PERSONA_AUTH_TOKEN = persona_sandbox_42 +# Program that converts Persona KYC data into the +# GNU Taler format. +KYC_PERSONA_CONVERTER_HELPER = taler-exchange-kyc-persona-converter.sh + # Form to use. KYC_PERSONA_TEMPLATE_ID = itempl_Uj6Xxxxx diff --git a/src/kyclogic/plugin_kyclogic_persona.c b/src/kyclogic/plugin_kyclogic_persona.c index 4f01ae40..35ab9ded 100644 --- a/src/kyclogic/plugin_kyclogic_persona.c +++ b/src/kyclogic/plugin_kyclogic_persona.c @@ -111,6 +111,12 @@ struct TALER_KYCLOGIC_ProviderDetails */ char *subdomain; + /** + * Name of the program we use to convert outputs + * from Persona into our JSON inputs. + */ + char *conversion_binary; + /** * Where to redirect the client upon completion. */ @@ -230,6 +236,12 @@ struct TALER_KYCLOGIC_ProofHandle */ char *url; + /** + * Handle to an external process that converts the + * Persona response to our internal format. + */ + struct TALER_JSON_ExternalConversion *ec; + /** * Hash of the payto:// URI we are checking the KYC for. */ @@ -246,6 +258,11 @@ struct TALER_KYCLOGIC_ProofHandle */ char *provider_user_id; + /** + * Account ID from the service. + */ + char *account_id; + /** * Inquiry ID at the provider. */ @@ -294,6 +311,11 @@ struct TALER_KYCLOGIC_WebhookHandle */ char *inquiry_id; + /** + * Account ID from the service. + */ + char *account_id; + /** * URL of the cURL request. */ @@ -315,6 +337,12 @@ struct TALER_KYCLOGIC_WebhookHandle */ const char *template_id; + /** + * Handle to an external process that converts the + * Persona response to our internal format. + */ + struct TALER_JSON_ExternalConversion *ec; + /** * Our account ID. */ @@ -344,6 +372,7 @@ persona_unload_configuration (struct TALER_KYCLOGIC_ProviderDetails *pd) GNUNET_free (pd->auth_token); GNUNET_free (pd->template_id); GNUNET_free (pd->subdomain); + GNUNET_free (pd->conversion_binary); GNUNET_free (pd->salt); GNUNET_free (pd->section); GNUNET_free (pd->post_kyc_redirect_url); @@ -418,6 +447,18 @@ persona_load_configuration (void *cls, persona_unload_configuration (pd); return NULL; } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (ps->cfg, + provider_section_name, + "KYC_PERSONA_CONVERTER_HELPER", + &pd->conversion_binary)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + provider_section_name, + "KYC_PERSONA_CONVERTER_HELPER"); + persona_unload_configuration (pd); + return NULL; + } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (ps->cfg, provider_section_name, @@ -838,8 +879,14 @@ persona_proof_cancel (struct TALER_KYCLOGIC_ProofHandle *ph) GNUNET_CURL_job_cancel (ph->job); ph->job = NULL; } + if (NULL != ph->ec) + { + TALER_JSON_external_conversion_stop (ph->ec); + ph->ec = NULL; + } GNUNET_free (ph->url); GNUNET_free (ph->provider_user_id); + GNUNET_free (ph->account_id); GNUNET_free (ph->inquiry_id); GNUNET_free (ph); } @@ -922,161 +969,6 @@ proof_reply_error (struct TALER_KYCLOGIC_ProofHandle *ph, } -/** - * Convert KYC attribute data from Persona response. - * - * @param attr json array with Persona attribute data - * @return KYC attribute data - */ -static json_t * -convert_attributes (const json_t *attr) -{ - const char *country_code = NULL; - const char *name_first = NULL; - const char *name_middle = NULL; - const char *name_last = NULL; - const char *address_street_1 = NULL; - const char *address_street_2 = NULL; - const char *address_city = NULL; - const char *address_postal_code = NULL; - const char *birthdate = NULL; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("country-code", - &country_code), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("name-first", - &name_first), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("name-middle", - &name_middle), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("name-last", - &name_last), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("address-street-1", - &address_street_1), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("address-street-2", - &address_street_2), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("address-city", - &address_city), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("address-postal-code", - &address_postal_code), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("birthdate", - &birthdate), - NULL), - GNUNET_JSON_spec_end () - }; - json_t *ret; - - if (GNUNET_OK != - GNUNET_JSON_parse (attr, - spec, - NULL, NULL)) - { - GNUNET_break (0); - json_dumpf (attr, - stderr, - JSON_INDENT (2)); - return NULL; - } - { - char *name = NULL; - char *street = NULL; - char *city = NULL; - - if ( (NULL != name_last) || - (NULL != name_first) || - (NULL != name_middle) ) - { - GNUNET_asprintf (&name, - "%s, %s %s", - (NULL != name_last) - ? name_last - : "", - (NULL != name_first) - ? name_first - : "", - (NULL != name_middle) - ? name_middle - : ""); - } - if ( (NULL != address_city) || - (NULL != address_postal_code) ) - { - GNUNET_asprintf (&city, - "%s%s%s %s", - (NULL != country_code) - ? country_code - : "", - (NULL != country_code) - ? "-" - : "", - (NULL != address_postal_code) - ? address_postal_code - : "", - (NULL != address_city) - ? address_city - : ""); - } - if ( (NULL != address_street_1) || - (NULL != address_street_2) ) - { - GNUNET_asprintf (&street, - "%s%s%s", - (NULL != address_street_1) - ? address_street_1 - : "", - ( (NULL != address_street_1) && - (NULL != address_street_2) ) - ? "\n" - : "", - (NULL != address_street_2) - ? address_street_2 - : ""); - } - ret = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ( - TALER_ATTRIBUTE_BIRTHDATE, - birthdate)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ( - TALER_ATTRIBUTE_FULL_NAME, - name)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ( - TALER_ATTRIBUTE_ADDRESS_STREET, - street)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ( - TALER_ATTRIBUTE_ADDRESS_CITY, - city)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ( - TALER_ATTRIBUTE_RESIDENCES, - country_code)) - ); - GNUNET_free (street); - GNUNET_free (city); - GNUNET_free (name); - } - return ret; -} - - /** * Return a response for the @a ph request indicating a * protocol violation by the Persona server. @@ -1115,6 +1007,86 @@ return_invalid_response (struct TALER_KYCLOGIC_ProofHandle *ph, } +/** + * Start the external conversion helper. + * + * @param pd configuration details + * @param attr attributes to give to the helper + * @param cb function to call with the result + * @param cb_cls closure for @a cb + * @return handle for the helper + */ +static struct TALER_JSON_ExternalConversion * +start_conversion (const struct TALER_KYCLOGIC_ProviderDetails *pd, + const json_t *attr, + TALER_JSON_JsonCallback cb, + void *cb_cls) +{ + return TALER_JSON_external_conversion_start ( + attr, + cb, + cb_cls, + pd->conversion_binary, + pd->conversion_binary, + "-a", + pd->auth_token, + NULL + ); +} + + +/** + * Type of a callback that receives a JSON @a result. + * + * @param cls closure with a `struct TALER_KYCLOGIC_ProofHandle *` + * @param status_type how did the process die + * @param code termination status code from the process + * @param result some JSON result, NULL if we failed to get an JSON output + */ +static void +proof_post_conversion_cb (void *cls, + enum GNUNET_OS_ProcessStatusType status_type, + unsigned long code, + const json_t *attr) +{ + struct TALER_KYCLOGIC_ProofHandle *ph = cls; + struct MHD_Response *resp; + struct GNUNET_TIME_Absolute expiration; + + ph->ec = NULL; + if ( (NULL == attr) || + (0 != code) ) + { + GNUNET_break_op (0); + return_invalid_response (ph, + MHD_HTTP_OK, + ph->inquiry_id, + "converter", + NULL); + persona_proof_cancel (ph); + return; + } + expiration = GNUNET_TIME_relative_to_absolute (ph->pd->validity); + resp = MHD_create_response_from_buffer (0, + "", + MHD_RESPMEM_PERSISTENT); + GNUNET_break (MHD_YES == + MHD_add_response_header (resp, + MHD_HTTP_HEADER_LOCATION, + ph->pd->post_kyc_redirect_url)); + TALER_MHD_add_global_headers (resp); + ph->cb (ph->cb_cls, + TALER_KYCLOGIC_STATUS_SUCCESS, + ph->account_id, + ph->inquiry_id, + expiration, + attr, + MHD_HTTP_SEE_OTHER, + resp); + persona_proof_cancel (ph); +} + + /** * Function called when we're done processing the * HTTP "/api/v1/inquiries/{inquiry-id}" request. @@ -1283,46 +1255,15 @@ handle_proof_finished (void *cls, data); break; } - - { - struct MHD_Response *resp; - struct GNUNET_TIME_Absolute expiration; - json_t *attr; - - attr = convert_attributes (attributes); - if (NULL == attr) - { - GNUNET_break_op (0); - return_invalid_response (ph, - response_code, - inquiry_id, - "data-relationships-account-data-id", - data); - break; - } - expiration = GNUNET_TIME_relative_to_absolute (ph->pd->validity); - resp = MHD_create_response_from_buffer (0, - "", - MHD_RESPMEM_PERSISTENT); - GNUNET_break (MHD_YES == - MHD_add_response_header (resp, - MHD_HTTP_HEADER_LOCATION, - ph->pd->post_kyc_redirect_url)); - TALER_MHD_add_global_headers (resp); - ph->cb (ph->cb_cls, - TALER_KYCLOGIC_STATUS_SUCCESS, - account_id, - inquiry_id, - expiration, - attr, - MHD_HTTP_SEE_OTHER, - resp); - json_decref (attr); - } + ph->account_id = GNUNET_strdup (account_id); + ph->ec = start_conversion (ph->pd, + j, + &proof_post_conversion_cb, + ph); GNUNET_JSON_parse_free (ispec); } GNUNET_JSON_parse_free (spec); - break; + return; /* continued in proof_post_conversion_cb */ } case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_NOT_FOUND: @@ -1580,6 +1521,12 @@ persona_webhook_cancel (struct TALER_KYCLOGIC_WebhookHandle *wh) GNUNET_CURL_job_cancel (wh->job); wh->job = NULL; } + if (NULL != wh->ec) + { + TALER_JSON_external_conversion_stop (wh->ec); + wh->ec = NULL; + } + GNUNET_free (wh->account_id); GNUNET_free (wh->inquiry_id); GNUNET_free (wh->url); GNUNET_free (wh); @@ -1650,6 +1597,32 @@ webhook_reply_error (struct TALER_KYCLOGIC_WebhookHandle *wh, } +/** + * Type of a callback that receives a JSON @a result. + * + * @param cls closure with a `struct TALER_KYCLOGIC_WebhookHandle *` + * @param status_type how did the process die + * @param code termination status code from the process + * @param result some JSON result, NULL if we failed to get an JSON output + */ +static void +webhook_post_conversion_cb (void *cls, + enum GNUNET_OS_ProcessStatusType status_type, + unsigned long code, + const json_t *attr) +{ + struct TALER_KYCLOGIC_WebhookHandle *wh = cls; + + wh->ec = NULL; + webhook_generic_reply (wh, + TALER_KYCLOGIC_STATUS_SUCCESS, + wh->account_id, + wh->inquiry_id, + attr, + MHD_HTTP_OK); +} + + /** * Function called when we're done processing the * HTTP "/api/v1/inquiries/{inquiry_id}" request. @@ -1723,7 +1696,6 @@ handle_webhook_finished (void *cls, NULL), GNUNET_JSON_spec_end () }; - json_t *attr; if (GNUNET_OK != GNUNET_JSON_parse (attributes, @@ -1807,19 +1779,15 @@ handle_webhook_finished (void *cls, MHD_HTTP_BAD_GATEWAY); break; } - - attr = convert_attributes (attributes); - webhook_generic_reply (wh, - TALER_KYCLOGIC_STATUS_SUCCESS, - account_id, - inquiry_id, - attr, - MHD_HTTP_OK); - json_decref (attr); + wh->account_id = GNUNET_strdup (account_id); + wh->ec = start_conversion (wh->pd, + j, + &webhook_post_conversion_cb, + wh); GNUNET_JSON_parse_free (ispec); } GNUNET_JSON_parse_free (spec); - break; + return; /* continued in webhook_post_conversion_cb */ } case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_NOT_FOUND: diff --git a/src/kyclogic/taler-exchange-kyc-persona-converter.sh b/src/kyclogic/taler-exchange-kyc-persona-converter.sh new file mode 100755 index 00000000..a5d4d03a --- /dev/null +++ b/src/kyclogic/taler-exchange-kyc-persona-converter.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# This file is in the public domain. +# +# This code converts (some of) the JSON output from Persona into the GNU Taler +# specific KYC attribute data (again in JSON format). We may need to download +# and inline file data in the process, for authorization pass "-a" with the +# respective bearer token. +# + +# Die if anything goes wrong. +set -eu + +# Parse command-line options +while getopts ':a:' OPTION; do + case "$OPTION" in + a) + TOKEN="$OPTARG" + ;; + ?) + echo "Unrecognized command line option" + exit 1 + ;; + esac +done + + +# First, extract everything from stdin. +J=$(jq '{"first":.data.attributes."name-first","middle":.data.attributes."name-middle","last":.data.attributes."name-last","cc":.data.attributes.fields."address-country-code".value,"birthdate":.data.attributes.birthdate,"city":.data.attributes."address-city","postcode":.data.attributes."address-postal-code","street-1":.data.attributes."address-street-1","street-2":.data.attributes."address-street-2","address-subdivision":.data.attributes."address-subdivision","identification-number":.data.attributes."identification-number","photo":.included[]|select(.type=="verification/government-id")|.attributes|select(.status=="passed")|."front-photo-url"}') + + +# Next, combine some fields into larger values. +FULLNAME=$(echo "$J" | jq -r '[.first,.middle,.last]|join(" ")') +STREET=$(echo $J | jq -r '[."street-1",."street-2"]|join(" ")') +CITY=$(echo $J | jq -r '[.postcode,.city,."address-subdivision,.cc"]|join(" ")') + +# Download and base32-encode the photo +PHOTO_URL=$(echo "$J" | jq -r '.photo') +PHOTO_FILE=$(mktemp -t tmp.XXXXXXXXXX) +if [ -z "${TOKEN:-}" ] +then + wget -q --output-document=- "$PHOTO_URL" | gnunet-base32 > ${PHOTO_FILE} +else + wget -q --output-document=- --header "Authorization: Bearer $TOKEN" "$PHOTO_URL" | gnunet-base32 > ${PHOTO_FILE} +fi + +# Combine into final result. +echo "$J" | jq \ + --arg full_name "${FULLNAME}" \ + --arg street "${STREET}" \ + --arg city "${CITY}" \ + --rawfile photo "${PHOTO_FILE}" \ + '{$full_name,$street,$city,"birthdate":.birthdate,"residences":.cc,"identification_number":."identification-number",$photo}' + +exit 0 diff --git a/src/util/.gitignore b/src/util/.gitignore index c5f8c76d..d79786ec 100644 --- a/src/util/.gitignore +++ b/src/util/.gitignore @@ -9,3 +9,4 @@ test_helper_cs test_helper_cs_home/ test_helper_eddsa test_helper_eddsa_home/ +test_conversion -- cgit v1.2.3