DCE, part one

This commit is contained in:
Florian Dold 2020-01-17 23:40:33 +01:00
parent f0d8311b1c
commit d95f2a9e43
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
9 changed files with 352 additions and 740 deletions

View File

@ -70,11 +70,6 @@ struct WireAccount
*/ */
struct TALER_BANK_AuthenticationData auth; struct TALER_BANK_AuthenticationData auth;
/**
* Our bank account number.
*/
struct TALER_Account account;
/** /**
* Name of the section that configures this account. * Name of the section that configures this account.
*/ */
@ -651,7 +646,6 @@ do_shutdown (void *cls)
wa_tail, wa_tail,
wa); wa);
TALER_BANK_auth_free (&wa->auth); TALER_BANK_auth_free (&wa->auth);
TALER_BANK_account_free (&wa->account);
GNUNET_free (wa->section_name); GNUNET_free (wa->section_name);
GNUNET_free (wa); GNUNET_free (wa);
} }
@ -2072,36 +2066,6 @@ process_account_cb (void *cls,
GNUNET_SCHEDULER_shutdown (); GNUNET_SCHEDULER_shutdown ();
return; return;
} }
if (GNUNET_OK !=
TALER_BANK_account_parse_cfg (cfg,
wa->section_name,
&wa->account))
{
GNUNET_break (0);
TALER_BANK_auth_free (&wa->auth);
GNUNET_free (wa->section_name);
GNUNET_free (wa);
fprintf (stderr,
"Failed to access bank account `%s'\n",
wa->section_name);
global_ret = 1;
GNUNET_SCHEDULER_shutdown ();
return;
}
if (TALER_PAC_X_TALER_BANK != wa->account.type)
{
GNUNET_break (0);
TALER_BANK_account_free (&wa->account);
TALER_BANK_auth_free (&wa->auth);
GNUNET_free (wa->section_name);
GNUNET_free (wa);
fprintf (stderr,
"Need x-taler-bank account URL in `%s'\n",
wa->section_name);
global_ret = 1;
GNUNET_SCHEDULER_shutdown ();
return;
}
GNUNET_CONTAINER_DLL_insert (wa_head, GNUNET_CONTAINER_DLL_insert (wa_head,
wa_tail, wa_tail,
wa); wa);

View File

@ -41,7 +41,6 @@ libtalerbank_la_SOURCES = \
bank_api_credit.c \ bank_api_credit.c \
bank_api_debit.c \ bank_api_debit.c \
bank_api_transfer.c \ bank_api_transfer.c \
bank_api_payto.c \
bank_api_parse.c bank_api_parse.c
libtalerbank_la_LIBADD = \ libtalerbank_la_LIBADD = \
$(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/json/libtalerjson.la \

View File

@ -23,58 +23,6 @@
#include "taler_bank_service.h" #include "taler_bank_service.h"
/**
* Convenience method for parsing configuration section with bank account data.
*
* @param cfg configuration to parse
* @param section the section with the configuration data
* @param acc[out] set to the account details
* @return #GNUNET_OK on success
*/
int
TALER_BANK_account_parse_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
const char *section,
struct TALER_Account *acc)
{
char *account_url;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
section,
"URL",
&account_url))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
section,
"URL");
return GNUNET_SYSERR;
}
if (TALER_EC_NONE !=
TALER_BANK_payto_to_account (account_url,
acc))
{
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
section,
"URL",
"Malformed payto:// URL for x-taler-bank method");
GNUNET_free (account_url);
return GNUNET_SYSERR;
}
if (TALER_PAC_X_TALER_BANK != acc->type)
{
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
section,
"URL",
"Malformed payto:// URL for x-taler-bank method");
GNUNET_free (account_url);
TALER_BANK_account_free (acc);
return GNUNET_SYSERR;
}
GNUNET_free (account_url);
return GNUNET_OK;
}
/** /**
* Parse configuration section with bank authentication data. * Parse configuration section with bank authentication data.
* *

View File

@ -1,466 +0,0 @@
/*
This file is part of TALER
(C) 2015--2020 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 <http://www.gnu.org/licenses/>
*/
/**
* @file bank-lib/bank_api_payto.c
* @brief Functions for parsing payto:// URIs
* @author Christian Grothoff <christian@grothoff.org>
*/
#include "platform.h"
#include "taler_util.h"
#include "taler_bank_service.h"
/**
* Maximum legal 'value' for an account number, based on IEEE double (for JavaScript compatibility).
*/
#define MAX_ACCOUNT_NO (1LLU << 52)
/**
* Release memory allocated in @a acc.
*
* @param acc account to free, the pointer itself is NOT free'd.
*/
void
TALER_BANK_account_free (struct TALER_Account *acc)
{
switch (acc->type)
{
case TALER_PAC_NONE:
return;
case TALER_PAC_X_TALER_BANK:
GNUNET_free (acc->details.x_taler_bank.hostname);
acc->details.x_taler_bank.hostname = NULL;
GNUNET_free (acc->details.x_taler_bank.account_base_url);
acc->details.x_taler_bank.account_base_url = NULL;
break;
case TALER_PAC_IBAN:
GNUNET_free (acc->details.iban.number);
acc->details.iban.number = NULL;
break;
}
acc->type = TALER_PAC_NONE;
}
/* Taken from GNU gettext */
/**
* Entry in the country table.
*/
struct CountryTableEntry
{
/**
* 2-Character international country code.
*/
const char *code;
/**
* Long English name of the country.
*/
const char *english;
};
/* Keep the following table in sync with gettext.
WARNING: the entries should stay sorted according to the code */
/**
* List of country codes.
*/
static const struct CountryTableEntry country_table[] = {
{ "AE", "U.A.E." },
{ "AF", "Afghanistan" },
{ "AL", "Albania" },
{ "AM", "Armenia" },
{ "AN", "Netherlands Antilles" },
{ "AR", "Argentina" },
{ "AT", "Austria" },
{ "AU", "Australia" },
{ "AZ", "Azerbaijan" },
{ "BA", "Bosnia and Herzegovina" },
{ "BD", "Bangladesh" },
{ "BE", "Belgium" },
{ "BG", "Bulgaria" },
{ "BH", "Bahrain" },
{ "BN", "Brunei Darussalam" },
{ "BO", "Bolivia" },
{ "BR", "Brazil" },
{ "BT", "Bhutan" },
{ "BY", "Belarus" },
{ "BZ", "Belize" },
{ "CA", "Canada" },
{ "CG", "Congo" },
{ "CH", "Switzerland" },
{ "CI", "Cote d'Ivoire" },
{ "CL", "Chile" },
{ "CM", "Cameroon" },
{ "CN", "People's Republic of China" },
{ "CO", "Colombia" },
{ "CR", "Costa Rica" },
{ "CS", "Serbia and Montenegro" },
{ "CZ", "Czech Republic" },
{ "DE", "Germany" },
{ "DK", "Denmark" },
{ "DO", "Dominican Republic" },
{ "DZ", "Algeria" },
{ "EC", "Ecuador" },
{ "EE", "Estonia" },
{ "EG", "Egypt" },
{ "ER", "Eritrea" },
{ "ES", "Spain" },
{ "ET", "Ethiopia" },
{ "FI", "Finland" },
{ "FO", "Faroe Islands" },
{ "FR", "France" },
{ "GB", "United Kingdom" },
{ "GD", "Caribbean" },
{ "GE", "Georgia" },
{ "GL", "Greenland" },
{ "GR", "Greece" },
{ "GT", "Guatemala" },
{ "HK", "Hong Kong" },
{ "HK", "Hong Kong S.A.R." },
{ "HN", "Honduras" },
{ "HR", "Croatia" },
{ "HT", "Haiti" },
{ "HU", "Hungary" },
{ "ID", "Indonesia" },
{ "IE", "Ireland" },
{ "IL", "Israel" },
{ "IN", "India" },
{ "IQ", "Iraq" },
{ "IR", "Iran" },
{ "IS", "Iceland" },
{ "IT", "Italy" },
{ "JM", "Jamaica" },
{ "JO", "Jordan" },
{ "JP", "Japan" },
{ "KE", "Kenya" },
{ "KG", "Kyrgyzstan" },
{ "KH", "Cambodia" },
{ "KR", "South Korea" },
{ "KW", "Kuwait" },
{ "KZ", "Kazakhstan" },
{ "LA", "Laos" },
{ "LB", "Lebanon" },
{ "LI", "Liechtenstein" },
{ "LK", "Sri Lanka" },
{ "LT", "Lithuania" },
{ "LU", "Luxembourg" },
{ "LV", "Latvia" },
{ "LY", "Libya" },
{ "MA", "Morocco" },
{ "MC", "Principality of Monaco" },
{ "MD", "Moldava" },
{ "MD", "Moldova" },
{ "ME", "Montenegro" },
{ "MK", "Former Yugoslav Republic of Macedonia" },
{ "ML", "Mali" },
{ "MM", "Myanmar" },
{ "MN", "Mongolia" },
{ "MO", "Macau S.A.R." },
{ "MT", "Malta" },
{ "MV", "Maldives" },
{ "MX", "Mexico" },
{ "MY", "Malaysia" },
{ "NG", "Nigeria" },
{ "NI", "Nicaragua" },
{ "NL", "Netherlands" },
{ "NO", "Norway" },
{ "NP", "Nepal" },
{ "NZ", "New Zealand" },
{ "OM", "Oman" },
{ "PA", "Panama" },
{ "PE", "Peru" },
{ "PH", "Philippines" },
{ "PK", "Islamic Republic of Pakistan" },
{ "PL", "Poland" },
{ "PR", "Puerto Rico" },
{ "PT", "Portugal" },
{ "PY", "Paraguay" },
{ "QA", "Qatar" },
{ "RE", "Reunion" },
{ "RO", "Romania" },
{ "RS", "Serbia" },
{ "RU", "Russia" },
{ "RW", "Rwanda" },
{ "SA", "Saudi Arabia" },
{ "SE", "Sweden" },
{ "SG", "Singapore" },
{ "SI", "Slovenia" },
{ "SK", "Slovak" },
{ "SN", "Senegal" },
{ "SO", "Somalia" },
{ "SR", "Suriname" },
{ "SV", "El Salvador" },
{ "SY", "Syria" },
{ "TH", "Thailand" },
{ "TJ", "Tajikistan" },
{ "TM", "Turkmenistan" },
{ "TN", "Tunisia" },
{ "TR", "Turkey" },
{ "TT", "Trinidad and Tobago" },
{ "TW", "Taiwan" },
{ "TZ", "Tanzania" },
{ "UA", "Ukraine" },
{ "US", "United States" },
{ "UY", "Uruguay" },
{ "VA", "Vatican" },
{ "VE", "Venezuela" },
{ "VN", "Viet Nam" },
{ "YE", "Yemen" },
{ "ZA", "South Africa" },
{ "ZW", "Zimbabwe" }
};
/**
* Country code comparator function, for binary search with bsearch().
*
* @param ptr1 pointer to a `struct table_entry`
* @param ptr2 pointer to a `struct table_entry`
* @return result of strncmp()'ing the 2-digit country codes of the entries
*/
static int
cmp_country_code (const void *ptr1,
const void *ptr2)
{
const struct CountryTableEntry *cc1 = ptr1;
const struct CountryTableEntry *cc2 = ptr2;
return strncmp (cc1->code,
cc2->code,
2);
}
/**
* Validates given IBAN according to the European Banking Standards. See:
* http://www.europeanpaymentscouncil.eu/documents/ECBS%20IBAN%20standard%20EBS204_V3.2.pdf
*
* @param iban the IBAN number to validate
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
*/
static int
validate_iban (const char *iban)
{
char cc[2];
char ibancpy[35];
struct CountryTableEntry cc_entry;
unsigned int len;
char *nbuf;
unsigned long long dividend;
unsigned long long remainder;
int nread;
int ret;
unsigned int i;
unsigned int j;
len = strlen (iban);
if (len > 34)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"IBAN number too long to be valid\n");
return GNUNET_NO;
}
strncpy (cc, iban, 2);
strncpy (ibancpy, iban + 4, len - 4);
strncpy (ibancpy + len - 4, iban, 4);
ibancpy[len] = '\0';
cc_entry.code = cc;
cc_entry.english = NULL;
if (NULL ==
bsearch (&cc_entry,
country_table,
sizeof (country_table) / sizeof (struct CountryTableEntry),
sizeof (struct CountryTableEntry),
&cmp_country_code))
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Country code `%c%c' not supported\n",
cc[0],
cc[1]);
return GNUNET_NO;
}
nbuf = GNUNET_malloc ((len * 2) + 1);
for (i = 0, j = 0; i < len; i++)
{
if (isalpha ((unsigned char) ibancpy[i]))
{
if (2 != snprintf (&nbuf[j],
3,
"%2u",
(ibancpy[i] - 'A' + 10)))
{
GNUNET_free (nbuf);
return GNUNET_NO;
}
j += 2;
continue;
}
nbuf[j] = ibancpy[i];
j++;
}
for (j = 0; '\0' != nbuf[j]; j++)
GNUNET_assert (isdigit ( (unsigned char) nbuf[j]));
GNUNET_assert (sizeof(dividend) >= 8);
remainder = 0;
for (unsigned int i = 0; i<j; i += 16)
{
if (1 !=
(ret = sscanf (&nbuf[i],
"%16llu %n",
&dividend,
&nread)))
{
GNUNET_free (nbuf);
GNUNET_break_op (0);
return GNUNET_NO;
}
if (0 != remainder)
dividend += remainder * (pow (10, nread));
remainder = dividend % 97;
}
GNUNET_free (nbuf);
if (1 == remainder)
return GNUNET_YES;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"IBAN checksum wrong\n");
return GNUNET_NO;
}
/**
* Parse payto://iban/ account URL (only account information,
* wire subject and amount are ignored).
*
* @param account_url URL to parse
* @param account[out] set to information, can be NULL
* @return #TALER_EC_NONE if @a account_url is well-formed
*/
static enum TALER_ErrorCode
parse_payto_iban (const char *account_url,
struct TALER_Account *account)
{
const char *iban;
const char *q;
char *result;
#define PREFIX "payto://iban/"
if (0 != strncasecmp (account_url,
PREFIX,
strlen (PREFIX)))
return TALER_EC_PAYTO_WRONG_METHOD;
iban = &account_url[strlen (PREFIX)];
#undef PREFIX
q = strchr (iban,
'?');
if (NULL != q)
{
result = GNUNET_strndup (iban,
q - iban);
}
else
{
result = GNUNET_strdup (iban);
}
if (GNUNET_OK !=
validate_iban (result))
{
GNUNET_free (result);
return TALER_EC_PAYTO_MALFORMED;
}
if (NULL != account)
{
account->type = TALER_PAC_IBAN;
account->details.iban.number = result;
}
else
{
GNUNET_free (result);
}
return TALER_EC_NONE;
}
/**
* Parse payto://x-taler-bank/ account URL (only account information,
* wire subject and amount are ignored).
*
* @param payto_url URL to parse
* @param account[out] set to information, can be NULL
* @return #TALER_EC_NONE if @a account_url is well-formed
*/
static enum TALER_ErrorCode
parse_payto_x_taler_bank (const char *payto_url,
struct TALER_Account *r_account)
{
#define PREFIX "payto://x-taler-bank/"
if (0 != strncasecmp (payto_url,
PREFIX,
strlen (PREFIX)))
return TALER_EC_PAYTO_WRONG_METHOD;
#undef PREFIX
r_account->details.x_taler_bank.hostname
= TALER_xtalerbank_base_url_from_payto (payto_url);
if (NULL == r_account->details.x_taler_bank.hostname)
return TALER_EC_PAYTO_MALFORMED;
r_account->details.x_taler_bank.account_base_url
= TALER_xtalerbank_account_url_from_payto (payto_url);
if (NULL == r_account->details.x_taler_bank.hostname)
{
GNUNET_free (r_account->details.x_taler_bank.hostname);
r_account->details.x_taler_bank.hostname = NULL;
return TALER_EC_PAYTO_MALFORMED;
}
r_account->type = TALER_PAC_X_TALER_BANK;
return TALER_EC_NONE;
}
typedef enum TALER_ErrorCode
(*Parser)(const char *account_url,
struct TALER_Account *r_account);
/**
* Parse @a payto_url and store the result in @a acc
*
* @param payto_url URL to parse
* @param acc[in,out] account to initialize, free using #TALER_BANK_account_free() later
* @return #TALER_EC_NONE if @a payto_url is well-formed
*/
enum TALER_ErrorCode
TALER_BANK_payto_to_account (const char *payto_url,
struct TALER_Account *acc)
{
Parser parsers[] = {
&parse_payto_x_taler_bank,
&parse_payto_iban,
NULL
};
for (unsigned int i = 0; NULL != parsers[i]; i++)
{
enum TALER_ErrorCode ec = parsers[i](payto_url,
acc);
if (TALER_EC_PAYTO_WRONG_METHOD == ec)
continue;
return ec;
}
return TALER_EC_PAYTO_WRONG_METHOD;
}
/* end of payto.c */

View File

@ -56,14 +56,6 @@ enum BenchmarkError
#define FIRST_INSTRUCTION -1 #define FIRST_INSTRUCTION -1
#define CMD_TRANSFER_TO_EXCHANGE(label, amount) \
TALER_TESTING_cmd_admin_add_incoming_retry \
(TALER_TESTING_cmd_admin_add_incoming (label, amount, \
exchange_bank_account.details. \
x_taler_bank.account_base_url, \
NULL, \
user_payto_url))
/** /**
* What mode should the benchmark run in? * What mode should the benchmark run in?
@ -90,7 +82,7 @@ enum BenchmarkMode
/** /**
* Hold information regarding which bank has the exchange account. * Hold information regarding which bank has the exchange account.
*/ */
static struct TALER_Account exchange_bank_account; static struct TALER_BANK_AuthenticationData exchange_bank_account;
/** /**
* Configuration of our exchange. * Configuration of our exchange.
@ -190,6 +182,18 @@ static char *remote_dir;
static int linger; static int linger;
static struct TALER_TESTING_Command
CMD_TRANSFER_TO_EXCHANGE (char *label, char *amount)
{
return TALER_TESTING_cmd_admin_add_incoming_retry
(TALER_TESTING_cmd_admin_add_incoming (label, amount,
exchange_bank_account.
wire_gateway_url,
NULL,
user_payto_url));
}
/** /**
* Decide which exchange account is going to be * Decide which exchange account is going to be
* used to address a wire transfer to. Used at * used to address a wire transfer to. Used at
@ -462,7 +466,7 @@ parallel_benchmark (TALER_TESTING_Main main_cb,
NULL == loglev ? "INFO" : loglev, NULL == loglev ? "INFO" : loglev,
logfile); logfile);
GNUNET_SCHEDULER_run (&launch_fakebank, GNUNET_SCHEDULER_run (&launch_fakebank,
exchange_bank_account.details.x_taler_bank.hostname); exchange_bank_account.wire_gateway_url);
exit (0); exit (0);
} }
if (-1 == fakebank) if (-1 == fakebank)
@ -855,26 +859,6 @@ main (int argc,
"url"); "url");
return BAD_CONFIG_FILE; return BAD_CONFIG_FILE;
} }
if (TALER_EC_NONE !=
TALER_BANK_payto_to_account (exchange_payto_url,
&exchange_bank_account))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_ ("Malformed payto:// URL `%s' in configuration\n"),
exchange_payto_url);
GNUNET_free (exchange_payto_url);
return BAD_CONFIG_FILE;
}
if (TALER_PAC_X_TALER_BANK != exchange_bank_account.type)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_ (
"Malformed payto:// URL `%s' in configuration: x-taler-bank required\n"),
exchange_payto_url);
GNUNET_free (exchange_payto_url);
return BAD_CONFIG_FILE;
}
} }
if ( (MODE_EXCHANGE == mode) || (MODE_BOTH == mode) ) if ( (MODE_EXCHANGE == mode) || (MODE_BOTH == mode) )
{ {

View File

@ -44,11 +44,6 @@ struct WireAccount
*/ */
struct WireAccount *prev; struct WireAccount *prev;
/**
* Account information.
*/
struct TALER_Account account;
/** /**
* Authentication data. * Authentication data.
*/ */
@ -471,19 +466,6 @@ add_account_cb (void *cls,
GNUNET_free (wa); GNUNET_free (wa);
return; return;
} }
if (GNUNET_OK !=
TALER_BANK_account_parse_cfg (cfg,
ai->section_name,
&wa->account))
{
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
"Failed to load account `%s'\n",
ai->section_name);
TALER_BANK_auth_free (&wa->auth);
GNUNET_free (wa->method);
GNUNET_free (wa);
return;
}
wa->section_name = GNUNET_strdup (ai->section_name); wa->section_name = GNUNET_strdup (ai->section_name);
GNUNET_CONTAINER_DLL_insert (wa_head, GNUNET_CONTAINER_DLL_insert (wa_head,
wa_tail, wa_tail,
@ -572,7 +554,6 @@ shutdown_task (void *cls)
GNUNET_CONTAINER_DLL_remove (wa_head, GNUNET_CONTAINER_DLL_remove (wa_head,
wa_tail, wa_tail,
wa); wa);
TALER_BANK_account_free (&wa->account);
TALER_BANK_auth_free (&wa->auth); TALER_BANK_auth_free (&wa->auth);
TALER_EXCHANGEDB_fees_free (wa->af); TALER_EXCHANGEDB_fees_free (wa->af);
GNUNET_free (wa->section_name); GNUNET_free (wa->section_name);

View File

@ -56,11 +56,6 @@ struct WireAccount
*/ */
char *section_name; char *section_name;
/**
* Account information.
*/
struct TALER_Account account;
/** /**
* Authentication data. * Authentication data.
*/ */
@ -212,7 +207,6 @@ shutdown_task (void *cls)
GNUNET_CONTAINER_DLL_remove (wa_head, GNUNET_CONTAINER_DLL_remove (wa_head,
wa_tail, wa_tail,
wa); wa);
TALER_BANK_account_free (&wa->account);
TALER_BANK_auth_free (&wa->auth); TALER_BANK_auth_free (&wa->auth);
GNUNET_free (wa->section_name); GNUNET_free (wa->section_name);
GNUNET_free (wa); GNUNET_free (wa);
@ -251,18 +245,6 @@ add_account_cb (void *cls,
GNUNET_free (wa); GNUNET_free (wa);
return; return;
} }
if (GNUNET_OK !=
TALER_BANK_account_parse_cfg (cfg,
ai->section_name,
&wa->account))
{
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
"Failed to load account `%s'\n",
ai->section_name);
TALER_BANK_auth_free (&wa->auth);
GNUNET_free (wa);
return;
}
wa->section_name = GNUNET_strdup (ai->section_name); wa->section_name = GNUNET_strdup (ai->section_name);
GNUNET_CONTAINER_DLL_insert (wa_head, GNUNET_CONTAINER_DLL_insert (wa_head,
wa_tail, wa_tail,

View File

@ -85,96 +85,11 @@ struct TALER_BANK_AuthenticationData
char *password; char *password;
} basic; } basic;
struct
{
/**
* Port that the fakebank runs on.
*/
uint16_t fb_port;
} fakebank;
} details; } details;
}; };
/**
* Different account types supported by payto://.
*/
enum TALER_PaytoAccountType
{
/**
* Used to indicate an uninitialized struct.
*/
TALER_PAC_NONE = 0,
/**
* Account type of a bank running the x-taler-bank protocol.
*/
TALER_PAC_X_TALER_BANK,
/**
* Account identified by IBAN number.
*/
TALER_PAC_IBAN
};
/**
* Information about an account extracted from a payto://-URL.
*/
struct TALER_Account
{
/**
* How this the account represented.
*/
enum TALER_PaytoAccountType type;
/**
* Internals depending on @e type.
*/
union
{
/**
* Taler bank address from x-taler-bank. Set if
* @e type is #TALER_AC_X_TALER_BANK.
*/
struct
{
/**
* Bank account base URL.
*/
char *account_base_url;
/**
* Only the hostname of the bank.
*/
char *hostname;
} x_taler_bank;
/**
* Taler bank address from iban. Set if
* @e type is #TALER_AC_IBAN.
*/
struct
{
/**
* IBAN number.
*/
char *number;
} iban;
} details;
};
/* ********************* /admin/add/incoming *********************** */ /* ********************* /admin/add/incoming *********************** */
@ -552,39 +467,6 @@ TALER_BANK_debit_history_cancel (struct TALER_BANK_DebitHistoryHandle *hh);
/* ******************** Convenience functions **************** */ /* ******************** Convenience functions **************** */
/**
* Convenience method for parsing configuration section with bank account data.
*
* @param cfg configuration to parse
* @param section the section with the configuration data
* @param acc[out] set to the account details
* @return #GNUNET_OK on success
*/
int
TALER_BANK_account_parse_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
const char *section,
struct TALER_Account *acc);
/**
* Release memory allocated in @a acc.
*
* @param acc account to free, the pointer itself is NOT free'd.
*/
void
TALER_BANK_account_free (struct TALER_Account *acc);
/**
* Parse @a payto_url and store the result in @a acc
*
* @param payto_url URL to parse
* @param acc[in,out] account to initialize, free using #TALER_BANK_account_free() later
* @return #TALER_EC_NONE if @a payto_url is well-formed
*/
enum TALER_ErrorCode
TALER_BANK_payto_to_account (const char *payto_url,
struct TALER_Account *acc);
/** /**
* Convenience method for parsing configuration section with bank * Convenience method for parsing configuration section with bank

View File

@ -24,6 +24,338 @@
#include "taler_json_lib.h" #include "taler_json_lib.h"
/* Taken from GNU gettext */
/**
* Entry in the country table.
*/
struct CountryTableEntry
{
/**
* 2-Character international country code.
*/
const char *code;
/**
* Long English name of the country.
*/
const char *english;
};
/* Keep the following table in sync with gettext.
WARNING: the entries should stay sorted according to the code */
/**
* List of country codes.
*/
static const struct CountryTableEntry country_table[] = {
{ "AE", "U.A.E." },
{ "AF", "Afghanistan" },
{ "AL", "Albania" },
{ "AM", "Armenia" },
{ "AN", "Netherlands Antilles" },
{ "AR", "Argentina" },
{ "AT", "Austria" },
{ "AU", "Australia" },
{ "AZ", "Azerbaijan" },
{ "BA", "Bosnia and Herzegovina" },
{ "BD", "Bangladesh" },
{ "BE", "Belgium" },
{ "BG", "Bulgaria" },
{ "BH", "Bahrain" },
{ "BN", "Brunei Darussalam" },
{ "BO", "Bolivia" },
{ "BR", "Brazil" },
{ "BT", "Bhutan" },
{ "BY", "Belarus" },
{ "BZ", "Belize" },
{ "CA", "Canada" },
{ "CG", "Congo" },
{ "CH", "Switzerland" },
{ "CI", "Cote d'Ivoire" },
{ "CL", "Chile" },
{ "CM", "Cameroon" },
{ "CN", "People's Republic of China" },
{ "CO", "Colombia" },
{ "CR", "Costa Rica" },
{ "CS", "Serbia and Montenegro" },
{ "CZ", "Czech Republic" },
{ "DE", "Germany" },
{ "DK", "Denmark" },
{ "DO", "Dominican Republic" },
{ "DZ", "Algeria" },
{ "EC", "Ecuador" },
{ "EE", "Estonia" },
{ "EG", "Egypt" },
{ "ER", "Eritrea" },
{ "ES", "Spain" },
{ "ET", "Ethiopia" },
{ "FI", "Finland" },
{ "FO", "Faroe Islands" },
{ "FR", "France" },
{ "GB", "United Kingdom" },
{ "GD", "Caribbean" },
{ "GE", "Georgia" },
{ "GL", "Greenland" },
{ "GR", "Greece" },
{ "GT", "Guatemala" },
{ "HK", "Hong Kong" },
{ "HK", "Hong Kong S.A.R." },
{ "HN", "Honduras" },
{ "HR", "Croatia" },
{ "HT", "Haiti" },
{ "HU", "Hungary" },
{ "ID", "Indonesia" },
{ "IE", "Ireland" },
{ "IL", "Israel" },
{ "IN", "India" },
{ "IQ", "Iraq" },
{ "IR", "Iran" },
{ "IS", "Iceland" },
{ "IT", "Italy" },
{ "JM", "Jamaica" },
{ "JO", "Jordan" },
{ "JP", "Japan" },
{ "KE", "Kenya" },
{ "KG", "Kyrgyzstan" },
{ "KH", "Cambodia" },
{ "KR", "South Korea" },
{ "KW", "Kuwait" },
{ "KZ", "Kazakhstan" },
{ "LA", "Laos" },
{ "LB", "Lebanon" },
{ "LI", "Liechtenstein" },
{ "LK", "Sri Lanka" },
{ "LT", "Lithuania" },
{ "LU", "Luxembourg" },
{ "LV", "Latvia" },
{ "LY", "Libya" },
{ "MA", "Morocco" },
{ "MC", "Principality of Monaco" },
{ "MD", "Moldava" },
{ "MD", "Moldova" },
{ "ME", "Montenegro" },
{ "MK", "Former Yugoslav Republic of Macedonia" },
{ "ML", "Mali" },
{ "MM", "Myanmar" },
{ "MN", "Mongolia" },
{ "MO", "Macau S.A.R." },
{ "MT", "Malta" },
{ "MV", "Maldives" },
{ "MX", "Mexico" },
{ "MY", "Malaysia" },
{ "NG", "Nigeria" },
{ "NI", "Nicaragua" },
{ "NL", "Netherlands" },
{ "NO", "Norway" },
{ "NP", "Nepal" },
{ "NZ", "New Zealand" },
{ "OM", "Oman" },
{ "PA", "Panama" },
{ "PE", "Peru" },
{ "PH", "Philippines" },
{ "PK", "Islamic Republic of Pakistan" },
{ "PL", "Poland" },
{ "PR", "Puerto Rico" },
{ "PT", "Portugal" },
{ "PY", "Paraguay" },
{ "QA", "Qatar" },
{ "RE", "Reunion" },
{ "RO", "Romania" },
{ "RS", "Serbia" },
{ "RU", "Russia" },
{ "RW", "Rwanda" },
{ "SA", "Saudi Arabia" },
{ "SE", "Sweden" },
{ "SG", "Singapore" },
{ "SI", "Slovenia" },
{ "SK", "Slovak" },
{ "SN", "Senegal" },
{ "SO", "Somalia" },
{ "SR", "Suriname" },
{ "SV", "El Salvador" },
{ "SY", "Syria" },
{ "TH", "Thailand" },
{ "TJ", "Tajikistan" },
{ "TM", "Turkmenistan" },
{ "TN", "Tunisia" },
{ "TR", "Turkey" },
{ "TT", "Trinidad and Tobago" },
{ "TW", "Taiwan" },
{ "TZ", "Tanzania" },
{ "UA", "Ukraine" },
{ "US", "United States" },
{ "UY", "Uruguay" },
{ "VA", "Vatican" },
{ "VE", "Venezuela" },
{ "VN", "Viet Nam" },
{ "YE", "Yemen" },
{ "ZA", "South Africa" },
{ "ZW", "Zimbabwe" }
};
/**
* Country code comparator function, for binary search with bsearch().
*
* @param ptr1 pointer to a `struct table_entry`
* @param ptr2 pointer to a `struct table_entry`
* @return result of strncmp()'ing the 2-digit country codes of the entries
*/
static int
cmp_country_code (const void *ptr1,
const void *ptr2)
{
const struct CountryTableEntry *cc1 = ptr1;
const struct CountryTableEntry *cc2 = ptr2;
return strncmp (cc1->code,
cc2->code,
2);
}
/**
* Validates given IBAN according to the European Banking Standards. See:
* http://www.europeanpaymentscouncil.eu/documents/ECBS%20IBAN%20standard%20EBS204_V3.2.pdf
*
* @param iban the IBAN number to validate
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
*/
static int
validate_iban (const char *iban)
{
char cc[2];
char ibancpy[35];
struct CountryTableEntry cc_entry;
unsigned int len;
char *nbuf;
unsigned long long dividend;
unsigned long long remainder;
int nread;
int ret;
unsigned int i;
unsigned int j;
len = strlen (iban);
if (len > 34)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"IBAN number too long to be valid\n");
return GNUNET_NO;
}
strncpy (cc, iban, 2);
strncpy (ibancpy, iban + 4, len - 4);
strncpy (ibancpy + len - 4, iban, 4);
ibancpy[len] = '\0';
cc_entry.code = cc;
cc_entry.english = NULL;
if (NULL ==
bsearch (&cc_entry,
country_table,
sizeof (country_table) / sizeof (struct CountryTableEntry),
sizeof (struct CountryTableEntry),
&cmp_country_code))
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Country code `%c%c' not supported\n",
cc[0],
cc[1]);
return GNUNET_NO;
}
nbuf = GNUNET_malloc ((len * 2) + 1);
for (i = 0, j = 0; i < len; i++)
{
if (isalpha ((unsigned char) ibancpy[i]))
{
if (2 != snprintf (&nbuf[j],
3,
"%2u",
(ibancpy[i] - 'A' + 10)))
{
GNUNET_free (nbuf);
return GNUNET_NO;
}
j += 2;
continue;
}
nbuf[j] = ibancpy[i];
j++;
}
for (j = 0; '\0' != nbuf[j]; j++)
GNUNET_assert (isdigit ( (unsigned char) nbuf[j]));
GNUNET_assert (sizeof(dividend) >= 8);
remainder = 0;
for (unsigned int i = 0; i<j; i += 16)
{
if (1 !=
(ret = sscanf (&nbuf[i],
"%16llu %n",
&dividend,
&nread)))
{
GNUNET_free (nbuf);
GNUNET_break_op (0);
return GNUNET_NO;
}
if (0 != remainder)
dividend += remainder * (pow (10, nread));
remainder = dividend % 97;
}
GNUNET_free (nbuf);
if (1 == remainder)
return GNUNET_YES;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"IBAN checksum wrong\n");
return GNUNET_NO;
}
/**
* Valudate payto://iban/ account URL (only account information,
* wire subject and amount are ignored).
*
* @param account_url URL to parse
* @return #GNUNET_YES if @a account_url is a valid payto://iban URI,
* #GNUNET_NO if @a account_url is a payto URI of a different type,
* #GNUNET_SYSERR if the IBAN (checksum) is incorrect
*/
int
validate_payto_iban (const char *account_url)
{
const char *iban;
const char *q;
char *result;
#define PREFIX "payto://iban/"
if (0 != strncasecmp (account_url,
PREFIX,
strlen (PREFIX)))
return GNUNET_NO;
iban = &account_url[strlen (PREFIX)];
#undef PREFIX
q = strchr (iban,
'?');
if (NULL != q)
{
result = GNUNET_strndup (iban,
q - iban);
}
else
{
result = GNUNET_strdup (iban);
}
if (GNUNET_OK !=
validate_iban (result))
{
GNUNET_free (result);
return GNUNET_SYSERR;
}
GNUNET_free (result);
return GNUNET_YES;
}
/** /**
* Compute the hash of the given wire details. The resulting * Compute the hash of the given wire details. The resulting
* hash is what is put into the contract. * hash is what is put into the contract.
@ -88,6 +420,12 @@ TALER_JSON_exchange_wire_signature_check (const json_t *wire_s,
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
if (GNUNET_SYSERR == validate_payto_iban (payto_url))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
return TALER_exchange_wire_signature_check (payto_url, return TALER_exchange_wire_signature_check (payto_url,
master_pub, master_pub,
&master_sig); &master_sig);